I've seen this:
How can you dynamically select a table with entity framework 4.x?
However I cannot use a base class in my situation. I am looking to create a user group and week sensitive table for auditing, so I cannot know what these will be called prior to them being created at runtime.
So if I login first week of the year, it would be:
Group1_01_2014
Is this possible? I've tried to simply change the database name at creation, but I get the standard exception about database migrations.
Thanks.
Edit: Before someone says splitting the database is silly, know that I'm auditing ALOT. The idea is to be able to audit most transactions, store them as long as needed, without severely affecting performance.
Edit2: That said if someone has a better solution I'm all ears.
Solution
Ended up using a stored procedure:.
CREATE FUNCTION GetAuditTableName
(
#db_code CHAR (4)
)
RETURNS CHAR (12)
BEGIN
DECLARE #wkNo CHAR (2)
DECLARE #year CHAR (4)
SELECT #wkNo = REPLACE(STR(DATEPART(WEEK, GETDATE()), 2), SPACE(1), '0')
SELECT #year = STR(DATEPART(YEAR, GETDATE()), 4)
RETURN #db_code + '_' + #year + '_' + #wkNo
END
GO
CREATE PROCEDURE [dbo].[Audit_Insert]
#audi_id_first NVARCHAR (20),
#audi_id_second NVARCHAR (20),
#audi_by NVARCHAR (100),
#audi_on DATETIME,
#audi_details XML,
#tabn_code CHAR (4),
#audt_id INT,
#audi_db_code CHAR (4)
AS
BEGIN
DECLARE #tableName CHAR (12)
SET #tableName = [dbo].GetAuditTableName(#audi_db_code)
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name=#tableName and xtype='U')
BEGIN
DECLARE #createSql NVARCHAR(MAX);
SELECT #createSql = 'CREATE TABLE [dbo].' + QUOTENAME(#tableName) + ' (
[audi_id] INT IDENTITY (1, 1) NOT NULL,
[audi_id_first] NVARCHAR (20) NULL,
[audi_id_second] NVARCHAR (20) NULL,
[audi_by] NVARCHAR (100) NOT NULL,
[audi_on] DATETIME NOT NULL,
[audi_details] XML NULL,
[tabn_code] CHAR (4) NULL,
[audt_id] INT NOT NULL,
CONSTRAINT [PK_dbo.' + #tableName + '] PRIMARY KEY CLUSTERED ([audi_id] ASC),
CONSTRAINT [FK_dbo.' + #tableName + '_dbo.tabn_table_name_tabn_code] FOREIGN KEY ([tabn_code]) REFERENCES [dbo].[tabn_table_name] ([tabn_code]),
CONSTRAINT [FK_dbo.' + #tableName + '_dbo.audt_audit_type_audt_id] FOREIGN KEY ([audt_id]) REFERENCES [dbo].[audt_audit_type] ([audt_id])
)'
EXEC sp_executesql #createSql
END
DECLARE #insertSql NVARCHAR(MAX);
SELECT #insertSql = N'INSERT [dbo].' + QUOTENAME(#tableName) + ' ([audi_id_first], [audi_id_second], [audi_by], [audi_on], [audi_details], [tabn_code], [audt_id])
VALUES (#audi_id_first, #audi_id_second, #audi_by, #audi_on, #audi_details, #tabn_code, #audt_id)'
EXEC sp_executesql #insertSql, N'#audi_id_first NVARCHAR (20), #audi_id_second NVARCHAR (20), #audi_by NVARCHAR (100), #audi_on DATETIME, #audi_details XML, #tabn_code CHAR (4), #audt_id INT', #audi_id_first, #audi_id_second, #audi_by, #audi_on, #audi_details, #tabn_code, #audt_id
DECLARE #idSql NVARCHAR(MAX);
SELECT #idSql = 'DECLARE #audi_id INT
SELECT #audi_id = [audi_id]
FROM [dbo].' + QUOTENAME(#tableName) + '
WHERE ##ROWCOUNT > 0 AND [audi_id] = scope_identity()
SELECT t0.[audi_id]
FROM [dbo].' + QUOTENAME(#tableName) + ' AS t0
WHERE ##ROWCOUNT > 0 AND t0.[audi_id] = #audi_id'
EXEC sp_executesql #idSql
END
GO
then calling this from C#:
public void AddRecord(Audit record)
{
var Id1 = new SqlParameter("#audi_id_first", SqlDbType.NVarChar);
Id1.Value = (object)record.Id1 ?? System.DBNull.Value;
var Id2 = new SqlParameter("#audi_id_second", SqlDbType.NVarChar);
Id2.Value = (object)record.Id2 ?? System.DBNull.Value;
var UserName = new SqlParameter("#audi_by", SqlDbType.NVarChar);
UserName.Value = record.UserName;
var Stamp = new SqlParameter("#audi_on", SqlDbType.DateTime);
Stamp.Value = record.Stamp;
var Details = new SqlParameter("#audi_details", SqlDbType.Xml);
Details.Value = (object)record.Details ?? System.DBNull.Value;
var TableCode = new SqlParameter("#tabn_code", SqlDbType.Char);
TableCode.Value = record.TableCode;
var TypeId = new SqlParameter("#audt_id", SqlDbType.Int);
TypeId.Value = record.TypeId;
var DatabaseCode = new SqlParameter("#audi_db_code", SqlDbType.Char);
DatabaseCode.Value = CallingPrefix;
this.Database.ExecuteSqlCommand("EXEC Audit_Insert #audi_id_first, #audi_id_second, #audi_by, #audi_on, #audi_details, #tabn_code, #audt_id, #audi_db_code",
Id1, Id2, UserName, Stamp, Details, TableCode, TypeId, DatabaseCode);
}
My next struggle is getting it to work with IQueryable OData requests.
Solution 2
CREATE PROCEDURE [dbo].[CreateAuditTableIfNoneExists]
#tableName CHAR (12)
AS
BEGIN
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name=#tableName and xtype='U')
BEGIN
DECLARE #createSql NVARCHAR(MAX);
SELECT #createSql = 'CREATE TABLE [dbo].' + QUOTENAME(#tableName) + ' (
[audi_id] INT IDENTITY (1, 1) NOT NULL,
[audi_id_first] NVARCHAR (20) NULL,
[audi_id_second] NVARCHAR (20) NULL,
[audi_by] NVARCHAR (100) NOT NULL,
[audi_on] DATETIME NOT NULL,
[audi_details] XML NULL,
[tabn_code] CHAR (4) NULL,
[audt_id] INT NOT NULL,
CONSTRAINT [PK_dbo.' + #tableName + '] PRIMARY KEY CLUSTERED ([audi_id] ASC),
CONSTRAINT [FK_dbo.' + #tableName + '_dbo.tabn_table_name_tabn_code] FOREIGN KEY ([tabn_code]) REFERENCES [dbo].[tabn_table_name] ([tabn_code]),
CONSTRAINT [FK_dbo.' + #tableName + '_dbo.audt_audit_type_audt_id] FOREIGN KEY ([audt_id]) REFERENCES [dbo].[audt_audit_type] ([audt_id])
)'
EXEC sp_executesql #createSql
END
END
and on database initialisation make sure the table is present:
public class AuditInitialiser : IDatabaseInitializer<AuditContext>
{
public void InitializeDatabase(AuditContext context)
{
if (context.Database.CreateIfNotExists())
{
Seed(context);
}
var tableName = new SqlParameter("#tableName", SqlDbType.Char);
tableName.Value = context.AuditTableName;
context.Database.ExecuteSqlCommand("EXEC CreateAuditTableIfNoneExists #tableName", tableName);
}
However this only works for me because I am using an API, so is stateless and constructs the DbContext every time. This ensures the table is always present. Wouldn't work if I was doing my working out on a stated system.
I'm not a huge fan of stored procedures, but this might be a case where you want to use EF 6's (EF5??)'s ability to bind to stored procs. Then you could pass the table to use as parameter. See if this helps: How to call Stored Procedure in Entity Framework 6 (Code-First)?
(you could also perhaps use EntitySQL to solve this)
Related
I am trying to write a stored procedure to search through text fields of a table as follows:
TABLE: [User]
[Id] BIGINT PRIMARY KEY, IDENTITY (1, 1)
[Name] NVARCHAR(100) NOT NULL
[Email] NVARCHAR(100) NOT NULL, UNIQUE
The production database has many columns and a very large data set. The point of this SP is to speed up searching as much as practically possible.
What I tried:
EntityFrameworkCore LINQ queries.
Generating SQL on-the-fly using ADO .NET.
The stored procedure below.
The SP has yeilded the best results so far but the results are not accurate.
TEST SCRIPT
USE [TestDatabase]
--DELETE FROM [User] -- Commented for your safety.
DBCC CHECKIDENT ('[User]', RESEED, 0)
INSERT INTO [User] ([Name], [Email]) VALUES ('Name 01', 'Email01#Email.com')
INSERT INTO [User] ([Name], [Email]) VALUES ('Name 02', 'Email02#Email.com')
INSERT INTO [User] ([Name], [Email]) VALUES ('Name 03', 'Email03#Email.com')
EXECUTE SpUserSearch 0
EXECUTE SpUserSearch 1
EXECUTE SpUserSearch 0, NULL, NULL
EXECUTE SpUserSearch 1, NULL, NULL
EXECUTE SpUserSearch 0, 'Name 01', '#'
EXECUTE SpUserSearch 1, 'Name 01', '#'
RESULTS:
The first 4 queries should have returned ALL rows.
Query 1: Expected Rows: 3, Returned Rows: 0.
Query 2: Expected Rows: 3, Returned Rows: 0.
Query 3: Expected Rows: 3, Returned Rows: 0.
Query 4: Expected Rows: 3, Returned Rows: 0.
Query 5: Expected Rows: 1, Returned Rows: 3.
Query 6: Expected Rows: 3, Returned Rows: 3.
STORED PROCEDURE:
CREATE OR ALTER PROCEDURE SpUserSearch
#Condition BIT = 0, -- AND=0, OR=1.
#Name NVARCHAR(100) = NULL,
#Email NVARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #UseName BIT
DECLARE #UseEmail BIT
IF ((#Name IS NULL) OR (LEN(#Name) = 0)) SET #UseName = 0 ELSE SET #UseName = 1
IF ((#Email IS NULL) OR (LEN(#Email) = 0)) SET #UseEmail = 0 ELSE SET #UseEmail = 1
IF (#Condition = 0)
SELECT [Id], [Name], [Email]
FROM [User]
WHERE
((#UseName = 1) OR ([Name] LIKE '%' + #Name + '%'))
AND
((#UseEmail = 1) OR ([Email] LIKE '%' + #Email + '%'))
ELSE
SELECT [Id], [Name], [Email]
FROM [User]
WHERE
((#UseName = 1) OR ([Name] LIKE '%' + #Name + '%'))
OR
((#UseEmail = 1) OR ([Email] LIKE '%' + #Email + '%'))
RETURN (##ROWCOUNT)
END
There are two questions here:
What am I doing wrong in the SP logic?
Is this the most performant way to condition on the WHERE clause? I am not sure if CURSORs apply in this context.
Any advice would be appreciated.
Your logic is wrong: you need #UseName = 0 and #UseEmail = 0 in the AND half of the procedure. You also need to swap (#UseName = 1) OR to (#UseName = 1) AND in the OR half.
Although it's hard to say what the intention would be for #Condition if only one search value is supplied: what if [Name] or [Email] in the row is null?
CREATE OR ALTER PROCEDURE SpUserSearch
#Condition BIT = 0, -- AND=0, OR=1.
#Name NVARCHAR(100) = NULL,
#Email NVARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #UseName BIT
DECLARE #UseEmail BIT
IF ((#Name IS NULL) OR (LEN(#Name) = 0)) SET #UseName = 0 ELSE SET #UseName = 1
IF ((#Email IS NULL) OR (LEN(#Email) = 0)) SET #UseEmail = 0 ELSE SET #UseEmail = 1
IF (#Condition = 0)
SELECT [Id], [Name], [Email]
FROM [User]
WHERE
((#UseName = 0) OR ([Name] LIKE '%' + #Name + '%'))
AND
((#UseEmail = 0) OR ([Email] LIKE '%' + #Email + '%'))
ELSE
SELECT [Id], [Name], [Email]
FROM [User]
WHERE
((#UseName = 1) AND ([Name] LIKE '%' + #Name + '%'))
OR
((#UseEmail = 1) AND ([Email] LIKE '%' + #Email + '%'))
RETURN (##ROWCOUNT)
END
Performance-wise: this is never going to be great, because of the leading wildcard.
You may also get parameter-sniffing problems, for which the solution is usually to build the query dynamically, as I show in an answer to your other question.
Question 1
I think the problem is around the OR predicates inside the parenthesis in each condition, I believe it should be an AND predicate like shown below:
CREATE OR ALTER PROCEDURE SpUserSearch
#Condition BIT = 0, -- AND=0, OR=1.
#Name NVARCHAR(100) = NULL,
#Email NVARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #UseName BIT
DECLARE #UseEmail BIT
IF ((#Name IS NULL) OR (LEN(#Name) = 0)) SET #UseName = 0 ELSE SET #UseName = 1
IF ((#Email IS NULL) OR (LEN(#Email) = 0)) SET #UseEmail = 0 ELSE SET #UseEmail = 1
IF (#Condition = 0)
SELECT [Id], [Name], [Email]
FROM [User]
WHERE
((#UseName = 1) AND ([Name] LIKE '%' + #Name + '%'))
AND
((#UseEmail = 1) AND ([Email] LIKE '%' + #Email + '%'))
ELSE
SELECT [Id], [Name], [Email]
FROM [User]
WHERE
((#UseName = 1) AND ([Name] LIKE '%' + #Name + '%'))
OR
((#UseEmail = 1) AND ([Email] LIKE '%' + #Email + '%'))
RETURN (##ROWCOUNT)
END
Question 2
I agree with Larnu's comment that, because you're using those wildcards, you probably can't work much on performance.
#UseName and #UseEmail are not necessary. you can simply null the variable if it's a whitespace, and then make use of ISNULL under the WHERE along with the #Condition as well. (no need for the IF/ELSE
Here is the procedure wearing a swimming goggles :) :
CREATE OR ALTER PROCEDURE SpUserSearch
#Condition BIT = 0, -- AND=0, OR=1.
#Name NVARCHAR(100) = NULL,
#Email NVARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
-- this would covers NULL and Whitespace
SET #Name = CASE WHEN #Name IS NOT NULL AND LEN(#Name) = 0 THEN NULL ELSE '%' + #Name + '%' END
SET #Email = CASE WHEN #Email IS NOT NULL AND LEN(#Email) = 0 THEN NULL ELSE '%' + #Email + '%' END
SELECT [Id], [Name], [Email]
FROM
[User]
WHERE
(
#Condition = 0
AND
(
[Name] LIKE ISNULL(#Name, [Name])
AND [Email] LIKE ISNULL(#Email, [Email])
)
)
OR
(
#Condition = 1
AND
(
[Name] LIKE ISNULL(#Name, [Name])
OR [Email] LIKE ISNULL(#Email, [Email])
)
)
RETURN (##ROWCOUNT)
END
I have a procedure that can be changed dynamically by user for multi column and I write it in SQL when I run it. Everything is OK in SQL and Server Explorer in Visual Studio but when I want use it in C# and call it, it just return 0 always.
Can anybody help me?!
CREATE PROCEDURE [dbo].[PDaynamicActualBy2Column]
#Colname1 nvarchar(100),
#VarCol1 nvarchar(100),
#Colname2 nvarchar(100),
#VarCol2 nvarchar(100),
#VarWeekNum nvarchar(100)
as
DECLARE #temp nvarchar(1500)
set #temp='SELECT SUM([dbo].[WeekActualTemp].[ACTUAL]) from [dbo].[MAINTB] join [dbo].[WeekActualTemp] on [dbo].[MAINTB].[UQ]=[dbo].[WeekActualTemp].[UQ]
where [dbo].[WeekActualTemp].[WeekNO]='+#VarWeekNum+' And [dbo].[MAINTB].'+#Colname1+' = '''+#VarCol1+''' And [dbo].[MAINTB].'+#Colname2+' = '''+#VarCol2+''''
exec (#temp)
This does not address the problem in the C#, however, it does address the huge injection issue you have in your code. Like mentioned, don't inject your parameters and properly quote your dynamic object names. This results in something like the below:
CREATE PROC dbo.PDaynamicActualBy2Column #Colname1 sysname, #VarCol1 nvarchar(100), #Colname2 sysname, #VarCol2 nvarchar(100), #VarWeekNum int AS --Assumed #VarWeekNum is an int, as why else is it called "num"?
BEGIN
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET #SQL = N'SELECT SUM(WAT.Actual) AS ActualSum' + #CRLF +
N'FROM dbo.MAINTB MTB' + #CRLF +
N' JOIN dbo.WeekActualTemp WAT ON MTB.UQ = WAT.UQ' + #CRLF +
N'WHERE WAT.WeekNO = #VarWeekNum' + #CRLF +
N' AND MTD.' + QUOTENAME(#Colname1) + N' = #VarCol1' + #CRLF +
N' AND MTD.' + QUOTENAME(#Colname2) + N' = #VarCol2;';
--PRINT #SQL; Your Best Friend
EXEC sp_executesql #SQL, N'#VarCol1 nvarchar(100),#VarCol2 nvarchar(100),#VarWeekNum int', #VarCol1, #VarCol2, #VarWeekNum;
END;
GO
Because you're only returning a single scalar value, you could also use an OUTPUT parameter as well, instead of a SELECT to the display the value. This would look like the below:
CREATE PROC dbo.PDaynamicActualBy2Column #Colname1 sysname, #VarCol1 nvarchar(100), #Colname2 sysname, #VarCol2 nvarchar(100), #VarWeekNum int, #ActualSum int OUTPUT AS --Assumes Actual is an int in your table. Use an appropriate data type
BEGIN
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET #SQL = N'SELECT #ActualSum = SUM(WAT.Actual)' + #CRLF +
N'FROM dbo.MAINTB MTB' + #CRLF +
N' JOIN dbo.WeekActualTemp WAT ON MTB.UQ = WAT.UQ' + #CRLF +
N'WHERE WAT.WeekNO = #VarWeekNum' + #CRLF +
N' AND MTD.' + QUOTENAME(#Colname1) + N' = #VarCol1' + #CRLF +
N' AND MTD.' + QUOTENAME(#Colname2) + N' = #VarCol2;';
--PRINT #SQL; Your Best Friend
EXEC sp_executesql #SQL, N'#VarCol1 nvarchar(100),#VarCol2 nvarchar(100),#VarWeekNum int, #ActualSum int OUTPUT', #VarCol1, #VarCol2, #VarWeekNum, #ActualSum OUTPUT; --Again, assumes Actual is an int.
END;
GO
Notice, as mentioned in the comments, I get rid of the 3+ part naming for your columns, and alias your tables instead. I then use those aliases to reference to correct object. I've also put "Your best Friend" in the code, should you need to debug it.
Note: As mentioned in a different answer, zero is likely because the SP is returning 0 to mean success. This is a documented and intentional feature of Stored Procedures:
Unless documented otherwise, all system stored procedures return a value of 0. This indicates success and a nonzero value indicates failure.
As the SP above is likely successful, the RETURN value is 0; to denote success. You shouldn't be looking at the RETURN value, but the dataset, or in the latter example the OUTPUT parameter's value. I am sure there are questions on SO for how to use an OUTPUT parameter in linq.
Zero in return value of your stored procedure means it executed successfully.
You should return a value by "RETURN" statement or "SELECT" statement for table in return.
In LINQ you cannot call an SP that have a meta output that is dynamic, you have to write your SP with "select" output and make a model and then go to SP and edit it again.
Alter PROCEDURE [dbo].[PDaynamicActualBy2Column]
#Colname1 nvarchar(100),
#VarCol1 nvarchar(100),
#Colname2 nvarchar(100),
#VarCol2 nvarchar(100),
#VarWeekNum nvarchar(100)
as
DECLARE #temp nvarchar(1500)
set #temp='SELECT SUM([dbo].[WeekActualTemp].[ACTUAL]) from [dbo].[MAINTB] join [dbo].[WeekActualTemp] on [dbo].[MAINTB].[UQ]=[dbo].[WeekActualTemp].[UQ]
where [dbo].[WeekActualTemp].[WeekNO]='+#VarWeekNum+' And [dbo].[MAINTB].'+#Colname1+' = '''+#VarCol1+''' And [dbo].[MAINTB].'+#Colname2+' = '''+#VarCol2+''''
-- exec (#temp)
SELECT top 0
SUM([dbo].[WeekActualTemp].[ACTUAL]) as sum
from [dbo].[MAINTB] join [dbo].[WeekActualTemp] on [dbo].[MAINTB].[UQ]=[dbo].[WeekActualTemp].[UQ]
then import SP in your LINQ then comment "select" and uncomment "exec" .
I have created a user defined type (with script to CREATE) given below:
CREATE TABLE [dbo].[EmployeeMasters](
[ID] [int] IDENTITY(1,1) NOT NULL,
[EmployeeID] [varchar](max) NOT NULL,
[EmployeeFName] [varchar](max) NOT NULL,
[EmployeeLName] [varchar](max) NOT NULL,
[Photo] [image] NOT NULL)
On the same database I have created a procedure that uses this type:
create PROCEDURE EmpQuli_INSERT #EmployeeID varchar(Max),#EmployeeFName VARCHAR(MAX), #EmployeeLName VARCHAR(MAX),#Photo IMAGE AS BEGIN DECLARE #NEWID VARCHAR(10);
DECLARE #PREFIX VARCHAR(MAX);
SET #PREFIX = UPPER(SUBSTRING('STR',1, 3)) SELECT #NEWID = (#PREFIX + replicate('0', 3 -len(CONVERT(VARCHAR,N.OID + 1))) + CONVERT(VARCHAR,N.OID + 1)) FROM (SELECT CASE WHEN MAX(T.TID) IS null then 0 else MAX(T.TID) end as OID FROM (SELECT SUBSTRING(EmployeeID, 3, 1) as PRE_FIX,SUBSTRING(EmployeeID, 3, LEN(EmployeeID))as TID FROM EmployeeMasters) AS T WHERE T.PRE_FIX = #PREFIX) AS N
insert into EmployeeMasters values(#NEWID,#EmployeeFName, #EmployeeLName, #Photo);
end
And I try to insert a value in c# I getting operand type clash : image is incomplate with varchar(max) in sql server
The c# code is:
EmployeeFName.Value = textBox_emp_Fname.Text;
EmployeeLName.Value = textBox_emp_Lname.Text;
Photo.Value =img_arr1;
AddEmployee.CommandText = "EmpQuli_INSERT #EmployeeFName, #EmployeeLName, #Photo";
I don't know who to fix it. Please help me because I have to submit my final year project on June first week but now I struggle this exception please help....
You're missing a column in your insert statement:
insert into EmployeeMasters values(#NEWID,#EmployeeFName, #EmployeeLName, #Photo);
EmployeeID is missing, so #Photo tries to save into #EmployeeLName, which is incompatible. Even if it weren't, you'd still be missing EmployeeID, which is NOT NULL.
I'd suggest using the explicit insert syntax instead of relying on the auto-supplied columns:
insert into EmployeeMasters(EmployeeID, EmployeeFName, EmployeeLName, Photo)
values (#NewID, #EmployeeFName, #EmployeeLName, #Photo);
I am stuck in this condition unable to insert into the table tbl_customer its giving error :
Arithmetic overflow error converting expression to data type int.
The statement has been terminated.
here is my table structure:
create table tbl_customer(
id int identity primary key,
cust_name varchar(50) NOT NULL,
filecode varchar(20) NOT NULL,
cust_mobile int,
cust_cnic varchar(50) NOT NULL,
cust_phone int,
cust_address varchar(200)
)
and here is the code i use to insert:
insert into tbl_customer values('Jonah Gordian','LHR001',03451119182,'11-22112-122',1212121212,'abc street 12')
and I used this code in c# to try inserting:
connclass.insert("insert into tbl_customer(cust_name,filecode,cust_mobile,cust_cnic,cust_phone,cust_address) VALUES('" + txtname.Text + "','" + txtfilecode.Text + "','" + int.Parse(txtmob.Text) + "','" + txtcnic.Text + "','" + int.Parse(txtphone.Text) + "','" + txtaddress.Text + "')");
create table tbl_customer(
id int identity primary key,
cust_name varchar(50) NOT NULL,
filecode varchar(20) NOT NULL,
cust_mobile varchar(20),
cust_cnic varchar(50) NOT NULL,
cust_phone varchar(20),
cust_address varchar(200)
)
insert into tbl_customer
(cust_name, filecode, cust_mobile, cust_cnic, cust_phone, cust_address )
values
('Jonah Gordian','LHR001','03451119182','11-22112-122','1212121212','abc street 12');
And also C# code is open to SQL injection attack, use parameters instead. ie:
string sql = #"insert into tbl_customer
(cust_name,filecode,cust_mobile,cust_cnic,cust_phone,cust_address)
VALUES
(#cust_name,#filecode,#cust_mobile,#cust_cnic,#cust_phone,#cust_address)";
using (SqlConnection con = new SqlConnection(#"server=.\SQLExpress;database=yourDbName;Trusted_Connection=yes"))
{
var cmd = new SqlCommand(sql, con);
cmd.Parameters.AddWithValue("#cust_name", txtname.Text);
cmd.Parameters.AddWithValue("#filecode", txtfilecode.Text);
cmd.Parameters.AddWithValue("#cust_mobile", txtmob.Text);
cmd.Parameters.AddWithValue("#cust_cnic", txtcnic.Text);
cmd.Parameters.AddWithValue("#cust_phone", txtphone.Text);
cmd.Parameters.AddWithValue("#cust_address", txtaddress.Text);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
You define cust_mobile as int, but try to insert 03451119182, which is clearly over the limit of 2147483647.
Change to bigint or store as a VarChar (including the leading zero).
Try like this,
CREATE TABLE tbl_customer (
id INT identity PRIMARY KEY
,cust_name VARCHAR(50) NOT NULL
,filecode VARCHAR(20) NOT NULL
,cust_mobile BIGINT --or Varchar(20)
,cust_cnic VARCHAR(50) NOT NULL
,cust_phone INT
,cust_address VARCHAR(200)
)
INSERT INTO tbl_customer
VALUES (
'Jonah Gordian'
,'LHR001'
,03451119182
,'11-22112-122'
,1212121212
,'abc street 12'
)
You have exceeded the int datatype limit. Change the datatype from int to either bigint or Varchar to resolve the issue.
Note: If you need leading Zeros then you can choose Varchar otherwise you can make use of BigInt.
You exceeded the limit of the int try with bigint
this value 3451119182
see in this link the limits
https://msdn.microsoft.com/pt-br/library/ms187745(v=sql.120).aspx
I want to run an ALTER TABLE that adds a default value constraint to a column.
I generate this statement dynamically from a .NET program.
How do I best format and quote the value when building my sql - now that ALTER TABLE statements does not support parameters (Gives the error 'Variables are not allowed in the ALTER TABLE statement').
Is there a utility for that in .NET? Or another solution?
You can do this in TSQL; for example, say you parameterize the command, passing in #DefaultValue, a varchar which may or may not be a valid TSQL literal. Because we are writing DDL, we will need to concatenate and exec, however we clearly don't want to blindly concatenate, as the value could be illegal. Fortunately, quotename does everything we need. By default, quotename outputs [qualified object names], but you can tell it to operate in literal escaping mode, for both single-quote and double-quote literals.
So our query that accepts #DefaultValue can build an SQL string:
declare #sql nvarchar(4000) = 'alter table ...';
-- ... blah
-- append the default value; note the result includes the outer quotes
#sql = #sql + quotename(#DefaultValue, '''');
-- ... blah
exec (#sql);
Full example:
--drop table FunkyDefaultExample
create table FunkyDefaultExample (id int not null)
declare #tableName varchar(20) = 'FunkyDefaultExample',
#colName varchar(20) = 'col name',
#defaultValue varchar(80) = 'test '' with quote';
-- the TSQL we want to generate to exec
/*
alter table [FunkyDefaultExample] add [col name] varchar(50) null
constraint [col name default] default 'test '' with quote';
*/
declare #sql nvarchar(4000) = 'alter table ' + quotename(#tablename)
+ ' add ' + quotename(#colName) + 'varchar(50) null constraint '
+ quotename(#colName + ' default') + ' default '
+ quotename(#defaultValue, '''');
exec (#sql);
-- tada!
string.Format("alter table YourTable add constraint DF_YourTable_Col1 default '{0}'",
inputValue.Replace("'", "''"));