Related
I have built a stored procedure that aims to identify duplicates in a table and to display the duplicated rows in a meaningful order. It looks like this:
CREATE PROCEDURE [dbo].[spFindDuplicates]
#tableName nvarchar(255),
#field1 nvarchar(255),
#field2 nvarchar(255) = '1',
#field3 nvarchar(255) = '2',
#field4 nvarchar(255) = '3',
#field5 nvarchar(255) = '4'
AS
BEGIN
DECLARE #query AS nvarchar(MAX);
SET #query = '
SELECT *
FROM ' + #tableName + '
WHERE CAST(' + #field1 + ' AS nvarchar(255)) + CAST(' + #field2 + ' AS nvarchar(255)) + CAST(' + #field3 + ' AS nvarchar(255)) + CAST(' + #field4 + ' AS nvarchar(255)) + CAST(' + #field5 + ' AS nvarchar(255))
IN
(
SELECT CAST(' + #field1 + ' AS nvarchar(255)) + CAST(' + #field2 + ' AS nvarchar(255)) + CAST(' + #field3 + ' AS nvarchar(255)) + CAST(' + #field4 + ' AS nvarchar(255)) + CAST(' + #field5 + ' AS nvarchar(255))
FROM ' + #tableName + '
GROUP BY CAST(' + #field1 + ' AS nvarchar(255)) + CAST(' + #field2 + ' AS nvarchar(255)) + CAST(' + #field3 + ' AS nvarchar(255)) + CAST(' + #field4 + ' AS nvarchar(255)) + CAST(' + #field5 + ' AS nvarchar(255))
HAVING COUNT(*) > 1
)
ORDER BY ' + #field1 + ', ' + #field2 + ', ' + #field3 + ', ' + #field4 + ', ' + #field5
EXECUTE(#query);
END
GO
--Example:
EXEC spFindDuplicates #tableName = 'someRandomTable', #field1 = 'firstField', #field2 = 'secondField', #field3 = 'thirdField'
As you can see, I can use at most 5 different fields that I concatenate in order for me to get a key used to determine whether we have a duplicate or not. Please note that I use the CAST function to be able to concatenate fields with various datatypes (varchar, int, dates, etc.).
When I execute the above stored procedure with 5 different fields, it works fine. But I would like to be able to run it with a variable number of fields (from 1 to 5), which is why I provided default values for #field2 to #field5.
But when I execute it with the above example (3 fields provided), I get the following error message:
A column has been specified more than once in the order by list. Columns in the order by list must be unique.
QUESTION: How can I keep ordering the resulting table without getting an error?
BONUS QUESTION: If you find a dynamic way to use that stored procedure with any number of fields (4, 17, or whatever), that'd be even more useful to me.
Like I said in the comments, injection is a huge problem here, and you need to consider it. Saying "Let's consider I don't mind about injection" is naïve and you need to change that attitude. Always make your SQL safe; then there are no excuses and chances for your application being compromised.
As what you are after, I suspect this achieves the goal. There's no need for the subquery to scan your table with an IN here, you can make use of COUNT and the OVER clause within a CTE.
CREATE PROCEDURE [dbo].[FindDuplicates] --I've removed te sp prefix, as sp_ is reserved by MS
#tableName sysname,
#field1 sysname,
#field2 sysname = NULL,
#field3 sysname = NULL,
#field4 sysname = NULL,
#field5 sysname = NULL
AS BEGIN
DECLARE #query AS nvarchar(MAX);
SET #query = N'WITH CTE AS(' + NCHAR(10) +
N' SELECT *' + NCHAR(10) +
N' COUNT(*) OVER (PARTITION BY ' + STUFF(CONCAT(N',' + QUOTENAME(#field1),N',' + QUOTENAME(#field2),N',' + QUOTENAME(#field3),N',' + QUOTENAME(#field4),N',' + QUOTENAME(#field5)),1,1,N'') + N' AS RowCount' + NCHAR(10) +
N' FROM ' + QUOTENAME(#tableName) + N')' + NCHAR(10) +
N'SELECT *' + NCHAR(10) +
N'FROM CTE' + NCHAR(10) +
N'WHERE RowCount > 1' + NCHAR(10) +
N'ORDER BY ' + STUFF(CONCAT(N',' + QUOTENAME(#field1),N',' + QUOTENAME(#field2),N',' + QUOTENAME(#field3),N',' + QUOTENAME(#field4),N',' + QUOTENAME(#field5)),1,1,N'') + N';';
PRINT #query;
--EXEC sys.sp_executesql #query; --Uncomment to rrun the actual query
END
GO
For the command you gave us EXEC dbo.FindDuplicates #tableName = 'someRandomTable', #field1 = 'firstField', #field2 = 'secondField', #field3 = 'thirdField';, this returns the SQL:
WITH CTE AS(
SELECT *
COUNT(*) OVER (PARTITION BY [firstField],[secondField],[thirdField] AS RowCount
FROM [someRandomTable])
SELECT *
FROM CTE
WHERE RowCount > 1
ORDER BY [firstField],[secondField],[thirdField];
Which, I believe gives you the behaviour you are after.
Edited the code to check if the column list exists on the sys.columns there by making sure we get only the columns which are appropriate.
CREATE FUNCTION dbo.fn_SplitString
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
ALTER PROCEDURE [dbo].[spFindDuplicates]
#tableName nvarchar(255),
#columnlist nvarchar(max)
AS
BEGIN
DECLARE #query AS nvarchar(MAX);
SET #columnlist = (SELECT STUFF((SELECT ','+'['+[name]+']'
FROM SYS.columns
WHERE object_id = object_id(#tableName)
AND [Name] IN
(
SELECT Item
FROM dbo.fn_SplitString(#columnlist,',')
)
FOR XML PATH('')
)
,1,1,''))
PRINT #columnlist
SET #query = 'SELECT * FROM (SELECT '+CAST(#columnlist AS NVARCHAR(MAX))+'
FROM '+CAST(#tableName AS nvarchar(MAX))+'
GROUP BY '+CAST(#columnlist AS NVARCHAR(MAX))+'
HAVING COUNT(*) > 1)Res1
ORDER BY '+#columnlist
EXEC SP_EXECUTESQL #query;
END
GO
I'm trying to create a stored procedure that compares 2 tables and makes them identical. I tried this code:
CREATE PROCEDURE SESUS.Compare2Tables
(#Table1 AS NVARCHAR(255),
#Table2 AS NVARCHAR(255),
#key AS NVARCHAR(MAX))
AS
BEGIN
IF OBJECT_ID ('tempdb..#tmp') IS NOT NULL
DROP TABLE #tmp
--print 'SELECT * INTO #tmp FROM ' + #Table2 + ' except select * from ' + #Table1 + ';'
--print 'delete from ' + #table1 + ' where ' + #key + ' in (select ' + #key + ' from #tmp);'
--print 'insert into ' +#table1 + ' select * from ' +#table2 + ' where ' +#key + ' in (select ' +#key + ' from #tmp);'
exec ('SELECT * INTO #tmp FROM ' + #Table2 + ' except select * from ' + #Table1 + ';')
exec ('delete from ' + #table1 + ' where ' + #key + ' in (select ' + #key + ' from #tmp)')
exec ('insert into ' +#table1 + ' select * from ' +#table2 + ' where ' +#key + ' in (select ' +#key + ' from #tmp)')
END
But it returns the following error, any idea why it could insert into this temporary table, but cannot select form it?
Invalid object name '#tmp'.
You can use MERGE statement to sync with the second table.
MERGE table1 AS target
USING table2 AS source
ON source.id = target.id
WHEN MATCHED THEN
UPDATE SET col1 = source.col1, col2 = ...
WHEN NOT MATCHED BY TARGET THEN
INSERT (id, col1, ...) VALUES (source.id, col1, ...)
WHEN NOT MATCHED BY SOURCE THEN
DELETE
;
try to execute all statements inside one execution because of the limited scope of temp tables:
exec ('SELECT * INTO #tmp FROM ' + #Table2 + ' except select * from ' + #Table1 + ';
delete from ' + #table1 + ' where ' + #key + ' in (select ' + #key + ' from #tmp)
insert into ' +#table1 + ' select * from ' +#table2 + ' where ' +#key + ' in (select ' +#key + ' from #tmp)')
You can also use global temp (##tmp) tables.
If your query returns null it fails to create temp table.
create Procedure SESUS.Compare2Tables(
#Table1 as NVarchar(255),
#Table2 as NVarchar(255),
#key as NVarchar(max)
)
AS
BEGIN
IF OBJECT_ID ('tempdb..#tmp') is not null
DROP TABLE #tmp
--print 'SELECT * INTO #tmp FROM ' + #Table2 + ' except select * from ' + #Table1 + ';'
--print 'delete from ' + #table1 + ' where ' + #key + ' in (select ' + #key + ' from #tmp);'
--print 'insert into ' +#table1 + ' select * from ' +#table2 + ' where ' +#key + ' in (select ' +#key + ' from #tmp);'
exec ('SELECT * INTO #tmp FROM ' + #Table2 + ' except select * from ' + #Table1 + ';')
If(OBJECT_ID('tempdb..#tmp') Is Not Null)
Begin
exec ('delete from ' + #table1 + ' where ' + #key + ' in (select ' + #key + ' from #tmp)')
exec ('insert into ' +#table1 + ' select * from ' +#table2 + ' where ' +#key + ' in (select ' +#key + ' from #tmp)')
End
END
I'm currently new to sql server.
I am using stored procedure with the help of visual studio 2010 express.
And i am experimenting on stored procedure in sql server when i found this error, which is very annoying :
Incorrect syntax near keyword 'IF
UPDATE [table_name]
SET
[delete_datetime] = CURRENT_TIMESTAMP,
[delete_user_record_id] = 2
WHERE [table_name].[record_id] = 2
Here's my stored procedure function. It is to update time stamps on my current table :
USE [MGroupIS]
GO
/****** Object: StoredProcedure [dbo].[iSP_SET_DATA_INFORMATION] Script Date: 02/01/2016 14:40:26 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[SP_SET_DATA_INFORMATION]
--Paramateres
AS
DECLARE #sql AS NVARCHAR(4000)
DECLARE #pFlag AS VARCHAR(6)
SET #pFlag = #flag
--IF Delete
IF #pFlag = 'DELETE'
BEGIN
SET #sql = 'UPDATE [' + #tableName + '] ' + CHAR(13) +
' SET ' + CHAR(13) +
' [delete_datetime] = CURRENT_TIMESTAMP, ' + CHAR(13) +
' [delete_user_record_id] = ' + CAST(#userRecordID AS VARCHAR(20)) + CHAR(13) +
' WHERE [' + #tableName + '].[' + #keyField + '] = ' + CAST(#recordID AS VARCHAR(20))
END
ELSE
BEGIN
SET #sql = 'UPDATE [' + #tableName + '] ' + CHAR(13) +
' SET ' + CHAR(13) +
' [edit_datetime] = CURRENT_TIMESTAMP, ' + CHAR(13) +
' [edit_user_record_id] = ' + CAST(#userRecordID AS CHAR(3))
END
EXEC sp_executeSQL #sql
PRINT #sql
And i call the stored procedure from another stored procedure (ISP_CFG_ACCESS_RIGHT_QUERY) :
ELSE IF #action = 'SAVE'
--SAVE Action
BEGIN
--If saved
IF #removeUnsaved = 0
BEGIN
UPDATE [CFG_ACCESS_RIGHT]
SET [CFG_ACCESS_RIGHT].[NAME] = '' + #name + '',
[CFG_ACCESS_RIGHT].[NOTE] = '' + #note + ''
WHERE [CFG_ACCESS_RIGHT].[RECORD_ID] = #recordID
DELETE FROM [CFG_ACCESS_RIGHT_DETAIL]
WHERE [CFG_ACCESS_RIGHT_DETAIL].[access_right_record_id] = #recordID
SET #sql = 'INSERT INTO [CFG_ACCESS_RIGHT_DETAIL] ' + CHAR(13) +
'SELECT * FROM [' + #tempTable + '] ' + CHAR(13) +
' WHERE [' + #tempTable + '].[delete_datetime] IS NULL;'
EXEC sp_executeSQL #sql
EXEC [ISP_SET_DATA_INFORMATION]
'CFG_ACCESS_RIGHT',
'record_id',
#userRecordID,
#recordID,
#voidStatus,
#voidReason,
#flag,
0
EXEC [ISP_SET_DATA_INFORMATION]
'CFG_ACCESS_RIGHT_DETAIL',
'access_right_record_id',
#userRecordID,
#recordID,
#voidStatus,
#voidReason,
#flag,
0
END
--If leave without saving
ELSE
BEGIN
EXEC [ISP_SET_DATA_INFORMATION]
'CFG_ACCESS_RIGHT',
'record_id',
#userRecordID,
#recordID,
#voidStatus,
#voidReason,
'DELETE',
0
END
Please help.
Thank you before hand.
Edit 1 : Isolating the potential problematic part. Please help
Your dynamic DROP table statement in procedure is syntactically wrong.
It should be like this,
IF OBJECT_ID('tablename', 'U') IS NOT NULL
DROP TABLE tablename;
In addition to that there are few syntax errors in your T-SQL too. I have fixed it.
Please refer this code,
IF #pFlag = 'DELETE'
BEGIN
SET #sql = 'UPDATE [' + #tableName + '] ' + Char(13)
+ ' SET ' + Char(13)
+ ' [delete_datetime] = CURRENT_TIMESTAMP, '
+ Char(13) + ' [delete_user_record_id] = '
+ Cast(#userRecordID AS VARCHAR(20))
+ Char(13) + ' WHERE [' + #tableName + '].['
+ #keyField + '] = '
+ Cast(#recordID AS VARCHAR(20))
END
ELSE
BEGIN
SET #sql = 'UPDATE [' + #tableName + '] ' + Char(13)
+ ' SET ' + Char(13)
+ ' [edit_datetime] = CURRENT_TIMESTAMP, '
+ Char(13) + ' [edit_user_record_id] = '
+ Cast(#userRecordID AS CHAR(3))
--IF New Record
IF #flag = 'NEW'
BEGIN
SET #sql = #sql + ', ' + Char(13)
+ '[create_datetime] = CURRENT_TIMESTAMP, '
+ Char(13) + '[create_user_record_id] = '
+ Cast(#userRecordID AS CHAR(3))
END
--IF Void Record
IF #voidStatus = 1
BEGIN
SET #sql = #sql + ', ' + Char(13) + '[void_status] = 1, '
+ Char(13)
+ '[void_datetime] = CURRENT_TIMESTAMP, '
+ Char(13) + '[void_user_record_id] = '
+ Cast(#userRecordID AS CHAR(3)) + ', '
+ Char(13) + '[void_reason] = ''' + #voidReason
+ ''''
END
ELSE
BEGIN
SET #sql = #sql + ', ' + Char(13) + '[void_status] = 0, '
+ Char(13) + '[void_datetime] = NULL, '
+ Char(13) + '[void_user_record_id] = '
+ Cast(#userRecordID AS CHAR(3)) + ', '
+ Char(13) + '[void_reason] = NULL'
END
--IF Print
IF #printed = 1
BEGIN
SET #sql = #sql + ', ' + Char(13)
+ '[print_count] = [print_count] + 1, '
+ Char(13) + '[last_print_datetime] = NULL, '
+ Char(13) + '[print_user_record_id] = 0'
+ Cast(#userRecordID AS CHAR(3))
END
SET #sql = #sql + ', ' + Char(13)
+ 'record_version = record_version + 1 '
+ Char(13) + ' WHERE [' + #tableName + '].['
+ #keyField + '] = '
+ Cast(#recordID AS VARCHAR(20))
END
EXEC Sp_executesql
#sql
PRINT #sql
Procedure Code:
ALTER PROCEDURE [dbo].[Sp_cfg_access_right_query] #recordID INT,
#userRecordID INT,
#action CHAR(4),
#flag CHAR(6),
#tempTable VARCHAR(50),
#name VARCHAR(50),
#note VARCHAR(1000),
#voidStatus BIT,
#voidReason VARCHAR(200),
#removeUnsaved BIT
AS
--Setting NULL values
SET #recordID = Isnull(#recordID, 0)
SET #userRecordID = Isnull(#recordID, 0)
SET #action = Isnull(#action, '')
SET #flag = Isnull(#flag, '')
SET #tempTable = Isnull(#tempTable, '')
SET #name = Isnull(#name, '')
SET #note = Isnull(#note, '')
SET #voidStatus = Isnull(#voidStatus, 0)
SET #voidReason = Isnull(#voidReason, '')
DECLARE #detailCount INT
DECLARE #currentID INT
DECLARE #sql NVARCHAR(1000)
DECLARE #temp VARCHAR(100)
DECLARE #tempConstraint VARCHAR(100)
IF #action = 'LOAD'
--LOAD action
BEGIN
SET #temp = 'CFG_TEMP_ARD_'
+ Replace(Cast(Newid() AS VARCHAR(50)), '-', '')
SET #tempConstraint = Cast(Year(CURRENT_TIMESTAMP) AS VARCHAR(4))
+ Cast(Month(CURRENT_TIMESTAMP) AS VARCHAR(2))
+ Cast(Day(CURRENT_TIMESTAMP) AS VARCHAR(2))
+ Cast(Datepart(HOUR, CURRENT_TIMESTAMP) AS VARCHAR(2))
+ Cast(Datepart(MINUTE, CURRENT_TIMESTAMP) AS VARCHAR(2))
+ Cast(Datepart(SECOND, CURRENT_TIMESTAMP) AS VARCHAR(2))
+ Cast(Datepart(MILLISECOND, CURRENT_TIMESTAMP) AS VARCHAR(3))
SET #sql = 'SELECT * INTO [' + #temp
+ '] FROM [CFG_ACCESS_RIGHT_DETAIL] WHERE 1=0;'
EXEC Sp_executesql
#sql
SET #sql = 'ALTER TABLE [' + #temp + '] ' + Char(13)
+ 'ADD CONSTRAINT PK_' + #tempConstraint
+ Char(13)
+ 'PRIMARY KEY ([record_id], [access_right_record_id]);'
EXEC Sp_executesql
#sql
IF #flag = 'NEW'
BEGIN
INSERT INTO [CFG_ACCESS_RIGHT]
(NAME,
note,
record_version)
VALUES ('',
'',
1)
SELECT #recordID = Scope_identity()
FROM [CFG_ACCESS_RIGHT];
END
SELECT #recordID currentID,
#temp tempTable
--Load Access Right
SELECT *
FROM [CFG_ACCESS_RIGHT]
WHERE [record_id] = #recordID
--Check & Return Detail Count
SELECT #detailCount = ##ROWCOUNT
FROM [CFG_ACCESS_RIGHT_DETAIL]
WHERE [access_right_record_id] = #recordID
SELECT Isnull(#detailCount, 0) detailCount
--Load Access Right Details if exist
IF #detailCount > 0
BEGIN
SELECT *
FROM [CFG_ACCESS_RIGHT_DETAIL]
WHERE [access_right_record_id] = #recordID
AND [delete_datetime] IS NULL
END
END
ELSE IF #action = 'SAVE'
--SAVE Action
BEGIN
--If saved
IF #removeUnsaved = 0
BEGIN
UPDATE [CFG_ACCESS_RIGHT]
SET [CFG_ACCESS_RIGHT].[NAME] = '' + #name + '',
[CFG_ACCESS_RIGHT].[NOTE] = '' + #note + ''
WHERE [CFG_ACCESS_RIGHT].[RECORD_ID] = #recordID
DELETE FROM [CFG_ACCESS_RIGHT_DETAIL]
WHERE [CFG_ACCESS_RIGHT_DETAIL].[access_right_record_id] = #recordID
SET #sql = 'INSERT INTO [CFG_ACCESS_RIGHT_DETAIL] '
+ Char(13) + 'SELECT * FROM [' + #tempTable + '] '
+ Char(13) + ' WHERE [' + #tempTable
+ '].[delete_datetime] IS NULL;'
EXEC Sp_executesql
#sql
EXEC [Sp_set_data_information]
'CFG_ACCESS_RIGHT',
'record_id',
#userRecordID,
#recordID,
#voidStatus,
#voidReason,
#flag,
0
EXEC [Sp_set_data_information]
'CFG_ACCESS_RIGHT_DETAIL',
'access_right_record_id',
#userRecordID,
#recordID,
#voidStatus,
#voidReason,
#flag,
0
END
--If leave without saving
ELSE
BEGIN
EXEC [Sp_set_data_information]
'CFG_ACCESS_RIGHT',
'record_id',
#userRecordID,
#recordID,
#voidStatus,
#voidReason,
'DELETE',
0
END
END
SET #sql ='IF OBJECT_ID(''' + #tempTable
+ ''', ''U'') IS NOT NULL
DROP TABLE ' + #tempTable
EXEC Sp_executesql
#sql
hello this my dynamic query and this procedure I did tested is working.
but Does not bring data to the server-side (entity)
visual studio 2012
framework 4.5
entity store procedure
public IEnumerable<spGetInvoiceDetailSearch_Result> GetInvoiceDetailedSearch(InvoiceModel item)
{
return DALContext.GetInvoiceDetailedSearch(item);
}
ALTER PROCEDURE [dbo].[spGetInvoiceDetailSearch] #InvoiceItemID INT
,#InvoiceTypeID INT
,#VesselID INT
,#PaidBy NVARCHAR(50)
,#InvoiceNo NVARCHAR(50)
,#CompanyID INT
,#InvoiceFromDate DATE
,#InvoiceToDate DATE
,#FromDueDate DATE
,#ToDueDate DATE
,#FromAmount DECIMAL(18, 4)
,#ToAmount DECIMAL(18, 4)
,#DueDateType NVARCHAR(50)
AS
BEGIN
DECLARE #SQLQuery AS NVARCHAR(4000)
SELECT #SQLQuery =
'SELECT dbo.Invoices.InvoiceID, dbo.Invoices.CompanyID, dbo.Invoices.VesselID, dbo.Invoices.InvoiceNo, dbo.Invoices.DueDate, dbo.Invoices.Amount,
dbo.Invoices.Comment, dbo.Invoices.IsPaid, dbo.Invoices.PaymentDate, dbo.Invoices.PaidBy, dbo.Invoices.Period, dbo.Invoices.InvoiceDate,
dbo.Invoices.InvoiceCurrencyCode, dbo.Invoices.InvoiceAmount, dbo.Invoices.IsReceived, dbo.Invoices.IsProforma, dbo.Invoices.InvoiceTypeID,
dbo.Invoices.IsDeleted, dbo.Invoices.Parity, dbo.Invoices.DueDateType, dbo.Vessels.Name AS VesselName, dbo.InvoiceVsInvoiceItems.ItemPrice as ItemPrice,
dbo.InvoiceVsInvoiceItems.InvoiceItemID as InvoiceItemID, dbo.InvoiceVsInvoiceItems.VAT as VAT, dbo.InvoiceVsInvoiceItems.ItemType as ItemType, dbo.InvoiceItems.Name AS InvoiceItemName,
dbo.Companies.Name AS CompanyName, dbo.InvoiceTypes.Name AS InvoiceTypeName
FROM dbo.Invoices LEFT OUTER JOIN
dbo.Companies ON dbo.Invoices.CompanyID = dbo.Companies.CompanyID LEFT OUTER JOIN
dbo.InvoiceTypes ON dbo.Invoices.InvoiceTypeID = dbo.InvoiceTypes.InvoiceTypeID LEFT OUTER JOIN
dbo.InvoiceVsInvoiceItems ON dbo.Invoices.InvoiceID = dbo.InvoiceVsInvoiceItems.InvoiceID LEFT OUTER JOIN
dbo.InvoiceItems ON dbo.InvoiceVsInvoiceItems.InvoiceVsInvoiceItemID = dbo.InvoiceItems.InvoiceItemID LEFT OUTER JOIN
dbo.Vessels ON dbo.Invoices.VesselID = dbo.Vessels.VesselID WHERE
dbo.Invoices.IsDeleted != 1
and dbo.Vessels.IsDeleted != 1
and dbo.Companies.IsDeleted != 1 '
SET FMTONLY OFF
IF #InvoiceItemID > 0
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.InvoiceItems.InvoiceItemID= ''' + CAST(#InvoiceItemID AS NVARCHAR(50)) + ''''
END
IF #InvoiceTypeID > 0
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.InvoiceTypeID= ''' + CAST(#InvoiceTypeID AS NVARCHAR(50)) + ''''
END
IF #VesselID > 0
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.VesselID= ''' + CAST(#VesselID AS NVARCHAR(50)) + ''''
END
IF #PaidBy IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + 'AND dbo.Invoices.PaidBy = ''' + CAST(#PaidBy AS NVARCHAR(50)) + ''''
END
IF #InvoiceNo IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + 'AND dbo.Invoices.InvoiceNo = ''' + CAST(#InvoiceNo AS NVARCHAR(50)) + ''''
END
IF #CompanyID > 0
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.CompanyID = ''' + CAST(#CompanyID AS NVARCHAR(50)) + ''''
END
IF #FromAmount IS NOT NULL AND #ToAmount IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.Amount BETWEEN ''' + CAST(#FromAmount AS NVARCHAR(100)) + ''' AND ''' + CAST(#ToAmount AS NVARCHAR(100)) + ''''
END
IF #DueDateType IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + 'AND dbo.Invoices.DueDateType = ''' + CAST(#DueDateType AS NVARCHAR(50)) + ''''
END
IF #InvoiceFromDate IS NOT NULL AND #InvoiceToDate IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.InvoiceDate Between ''' + CAST(#InvoiceFromDate AS NVARCHAR(100)) + ''' AND ''' + CAST(#InvoiceToDate AS NVARCHAR(100)) + ''''
END
IF #FromDueDate IS NOT NULL AND #ToDueDate IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.DueDate Between ''' + CAST(#FromDueDate AS NVARCHAR(100)) + ''' AND ''' + CAST(#ToDueDate AS NVARCHAR(100)) + ''''
END
EXECUTE (#SQLQuery)
END
and end question
my table date type : date format but
server shows it like datetime how can I do to change it to date format..
thank you
regards
ALTER PROCEDURE [dbo].[spGetInvoiceDetailSearch] #InvoiceItemID INT
,#InvoiceTypeID INT
,#VesselID INT
,#PaidBy NVARCHAR(50)
,#InvoiceNo NVARCHAR(50)
,#CompanyID INT
,#InvoiceFromDate DATE
,#InvoiceToDate DATE
,#FromDueDate DATE
,#ToDueDate DATE
,#FromAmount DECIMAL(18, 4)
,#ToAmount DECIMAL(18, 4)
,#DueDateType NVARCHAR(50)
AS
BEGIN
DECLARE #SQLQuery AS NVARCHAR(4000)
SELECT #SQLQuery =
'SELECT dbo.Invoices.InvoiceID, dbo.Invoices.CompanyID, dbo.Invoices.VesselID, dbo.Invoices.InvoiceNo, dbo.Invoices.DueDate, dbo.Invoices.Amount,
dbo.Invoices.Comment, dbo.Invoices.IsPaid, dbo.Invoices.PaymentDate, dbo.Invoices.PaidBy, dbo.Invoices.Period, dbo.Invoices.InvoiceDate,
dbo.Invoices.InvoiceCurrencyCode, dbo.Invoices.InvoiceAmount, dbo.Invoices.IsReceived, dbo.Invoices.IsProforma, dbo.Invoices.InvoiceTypeID,
dbo.Invoices.IsDeleted, dbo.Invoices.Parity, dbo.Invoices.DueDateType, dbo.Vessels.Name AS VesselName, dbo.InvoiceVsInvoiceItems.ItemPrice as ItemPrice,
dbo.InvoiceVsInvoiceItems.InvoiceItemID as InvoiceItemID, dbo.InvoiceVsInvoiceItems.VAT as VAT, dbo.InvoiceVsInvoiceItems.ItemType as ItemType, dbo.InvoiceItems.Name AS InvoiceItemName,
dbo.Companies.Name AS CompanyName, dbo.InvoiceTypes.Name AS InvoiceTypeName
FROM dbo.Invoices LEFT OUTER JOIN
dbo.Companies ON dbo.Invoices.CompanyID = dbo.Companies.CompanyID LEFT OUTER JOIN
dbo.InvoiceTypes ON dbo.Invoices.InvoiceTypeID = dbo.InvoiceTypes.InvoiceTypeID LEFT OUTER JOIN
dbo.InvoiceVsInvoiceItems ON dbo.Invoices.InvoiceID = dbo.InvoiceVsInvoiceItems.InvoiceID LEFT OUTER JOIN
dbo.InvoiceItems ON dbo.InvoiceVsInvoiceItems.InvoiceVsInvoiceItemID = dbo.InvoiceItems.InvoiceItemID LEFT OUTER JOIN
dbo.Vessels ON dbo.Invoices.VesselID = dbo.Vessels.VesselID WHERE
dbo.Invoices.IsDeleted != 1
and dbo.Vessels.IsDeleted != 1
and dbo.Companies.IsDeleted != 1 '
SET FMTONLY OFF
IF #InvoiceItemID > 0
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.InvoiceItems.InvoiceItemID= ' + CAST(#InvoiceItemID AS NVARCHAR(50)) + ''
END
IF #InvoiceTypeID > 0
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.InvoiceTypeID= ' + CAST(#InvoiceTypeID AS NVARCHAR(50)) + ''
END
IF #VesselID > 0
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.VesselID= ' + CAST(#VesselID AS NVARCHAR(50)) + ''
END
IF #PaidBy IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.PaidBy = ''' + CAST(#PaidBy AS NVARCHAR(50)) + ''''
END
IF #InvoiceNo IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.InvoiceNo = ''' + CAST(#InvoiceNo AS NVARCHAR(50)) + ''''
END
IF #CompanyID > 0
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.CompanyID = ' + CAST(#CompanyID AS NVARCHAR(50)) + ''
END
IF #FromAmount IS NOT NULL AND #ToAmount IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.Amount BETWEEN ''' + CAST(#FromAmount AS NVARCHAR(100)) + ''' AND ''' + CAST(#ToAmount AS NVARCHAR(100)) + ''''
END
IF #DueDateType IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.DueDateType = ''' + CAST(#DueDateType AS NVARCHAR(50)) + ''''
END
IF #InvoiceFromDate IS NOT NULL AND #InvoiceToDate IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.InvoiceDate Between ''' + CAST(#InvoiceFromDate AS NVARCHAR(100)) + ''' AND ''' + CAST(#InvoiceToDate AS NVARCHAR(100)) + ''''
END
IF #FromDueDate IS NOT NULL AND #ToDueDate IS NOT NULL
BEGIN
SET #SQLQuery = #SQLQuery + ' AND dbo.Invoices.DueDate Between ''' + CAST(#FromDueDate AS NVARCHAR(100)) + ''' AND ''' + CAST(#ToDueDate AS NVARCHAR(100)) + ''''
END
PRINT (#SQLQuery)
END
First of all, debugging it's very easy. Replace EXEC(#SQLQUery) with print and then you see your actual query.
You had some sintax error ( some places where AND was missing a space in front) and also you have some interger that were treated as strings.
Try my updated procedure.
It seems that procedure is getting called properly but no rows are getting returned, to debug the exact problem you can write actual hardcoded query returning 1 or more records instead of dynamic query.
So after doing that there are two possibilities
procedure call via edmx returns data, that means parameter values are causing some problem.
Any Data is not returned.
To solve any of the problem you need to check corresponding sql query which is getting generated while calling SP via Enitity Framework.
I have the following stored procedure which deletes and inserts rows in a table. It is running slow.
I have read various proposals and i have implemented:
Delete rows in batches and using derived table
Disable FK
Indexes on fields that are in the where clause.
So the way it should go is:
Tables have around 10 million records.
Every day i need to refresh around 15-30% of them. I use this SP to do it.
Source:
CREATE PROCEDURE [dbo].[spIncrementalUpdate]
-- Add the parameters for the stored procedure here
#table_inc nvarchar(30),
#table_target nvarchar(30),
#table_date nvarchar(30),
#field1 nvarchar(10),
#field2 nvarchar(10)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #logmessage as nvarchar(2048)
DECLARE #logdatacode as int
DECLARE #cmd as nvarchar(max)
DECLARE #fromjulian nvarchar(10)
DECLARE #datadate datetime
DECLARE #datadate_str nvarchar(10)
DECLARE #rows int
DECLARE #ParmDefinition nvarchar(500)
select #fromjulian = '114000'
print 'Using ' + #fromjulian
--
-- GET THE ROW COUNT OF THE INC TABLE.
--
IF #field2 = ''
BEGIN
SET #cmd = N'SELECT #retval = count(*) from ' +
#table_inc + ' where ' + #field1 +' > ' + #fromjulian
END
ELSE
BEGIN
SET #cmd = N'SELECT #retval = count(*) from ' +
#table_inc + ' where ' + #field1 +' > ' + #fromjulian +
' OR ' + #field2 +' > ' + #fromjulian
END
SET #ParmDefinition = N'#retval int OUTPUT'
EXEC sp_executesql #cmd, #ParmDefinition, #retval = #rows OUTPUT
--
if #rows <> 0
BEGIN
SET #logmessage = #table_inc + ' has ' +
cast(#rows as nvarchar(10)) +
' rows after ' + #fromjulian + ', deleting'
SET #logdatacode = 1000
--
-- Delete the records from original table based on #fromjulian
--
IF #field2 = ''
BEGIN
SET #cmd = N'delete ' + #table_target +
' from (select top(50000) * from ' + #table_target +
' where ' + #field1 + ' > ' + #fromjulian +
' order by ' + #field1 + ') ' +
#table_target
print #cmd
END
ELSE
BEGIN
SET #cmd = N'delete ' + #table_target +
' from (select top(50000) * from ' +
#table_target +
' where ' + #field1 + ' > ' + #fromjulian +
' OR ' + #field2 +' > ' + #fromjulian +
' order by ' + #field1 + ',' + #field2 + ') ' +
#table_target
print #cmd
END
SELECT 1
WHILE ##ROWCOUNT <> 0
BEGIN
EXEC sp_executesql #cmd
END
--
-- Inserting the records to target from INC table
--
IF #field2 = ''
BEGIN
SET #cmd = N'insert into ' + #table_target +
' select * from ' + #table_inc +
' where ' + #field1 +' > ' + cast(#fromjulian as nvarchar(10))
print #cmd
END
ELSE
BEGIN
SET #cmd = N'insert into ' + #table_target +
' select * from ' + #table_inc +
' where ' + #field1 +' > ' + cast(#fromjulian as nvarchar(10)) +
' OR ' + #field2 +' > ' + cast(#fromjulian as nvarchar(10))
print #cmd
END
print #cmd
EXEC sp_executesql #cmd
END
ELSE
BEGIN
SET #logmessage = 'NO ROWS IN ' + #table_inc + ' AFTER ' + cast(#fromjulian as nvarchar(10))
SET #logdatacode = 1001
END
--
-- LOG
--
INSERT INTO YLA_GROUP.[dbo].[sysssislog]
([event]
,[computer]
,[operator]
,[source]
,[sourceid]
,[executionid]
,[starttime]
,[endtime]
,[datacode]
,[databytes]
,[message])
VALUES
('spIncrementalUpdate','','','',NEWID(),NEWID(),getdate(),getdate(),#logdatacode,null,#logmessage)
print cast(#logdatacode as nvarchar(10)) + ' - ' + #logmessage
END
Since you are deleting rows in batches, you should remove the ORDER BY clause from your subquery because it is not necessary.
Here's the extract from your script:
IF #field2 = ''
BEGIN
SET #cmd = N'delete ' + #table_target +
' from (select top(50000) * from ' + #table_target +
' where ' + #field1 + ' > ' + #fromjulian + ') ' + #table_target
print #cmd
END
ELSE
BEGIN
SET #cmd = N'delete ' + #table_target +
' from (select top(50000) * from ' + #table_target +
' where ' + #field1 + ' > ' + #fromjulian +
' OR ' + #field2 +' > ' + #fromjulian + ') ' + #table_target
print #cmd
END
Remember that sorting can be an expensive operation, and even more expensive if you remove (correctly in this case) indexes.
Beyond that, there's not much you can do. Also consider that using dynamic SQL, execution plans are not cached. So, every time you execute the command inside #cmd the Query Engine needs to calculate the optimal execution plan. Unfortunately, as far as I can see, you need dynamic SQL.