Use #variable in COLUMN name in SQL SERVER 2012 - sql

Here, I've used SUM function on TRx1 column.
I've TRx2,3,4,..53 Columns in the table.
I want to display all the columns using loop.
DECLARE #flag INT;
SET #flag = 1;
WHILE #flag <= 2
BEGIN
select TOP 5 sd.OutletBPID, md.Product, SUM(TRx1)
from sdata as sd, md, oa
where sd.PSetID = md.PsetID
group by sd.OutletBPID, md.Product;
SET #flag = #flag + 1;
END;
The following code i did but it shows error: "Invalid Column Name"
DECLARE #flag INT;
SET #flag = 1;
WHILE #flag <= 2
BEGIN
select TOP 5 sd.OutletBPID, md.Product, SUM(TRx#flag)
from sdata as sd, md, oa
where sd.PSetID = md.PsetID
group by sd.OutletBPID, md.Product;
SET #flag = #flag + 1;
END;

You need dynamic sql
DECLARE #flag INT,
#sql varchar(8000)=''
SET #flag = 1;
WHILE #flag <= 2
BEGIN
SET #sql = 'select TOP 5 sd.OutletBPID, md.Product, SUM(TRx'+cast(#flag as varchar(20))+')
from sdata as sd, md, oa
where sd.PSetID = md.PsetID
group by sd.OutletBPID, md.Product'
exec (#sql)
SET #flag = #flag + 1;
END;

Related

SQL Server stored procedure running in infinite loop

I am running a stored procedure which is running infinitely.
I have used a while loop that seems to be running without ever ending.
CREATE PROCEDURE ABC
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Id INT;
DECLARE #iter INT = 1;
DECLARE #iterMax INT;
DECLARE #psubject VARCHAR(100);
DECLARE #pbody NVARCHAR(MAX);
DECLARE #pSendTo NVARCHAR(MAX);
DECLARE #pProfile VARCHAR(MAX);
IF OBJECT_ID('tempdB..#temp') IS NOT NULL
DROP TABLE #temp;
SET #pProfile = 'Test';
IF ((SELECT COUNT(*)
FROM [Table_A] R
JOIN [Table_B] T ON R.Id = T.r_Id
WHERE R.[Date] <= (DATEADD(DAY, -1, GETDATE()))
AND T.[Sent_Flag] IS NULL) >= 1)
BEGIN
SELECT IDENTITY(int, 1, 1) AS RecId,
[r_id] * 1 AS Id
INTO #temp
FROM [Table_A] R
JOIN [Table_B] T ON R.Id = T.r_Id
WHERE R.[Date] <= (DATEADD(DAY, -1, GETDATE()))
AND T.[Sent_Flag] IS NULL;
BEGIN
SET #iterMax = (SELECT COUNT(*)FROM #temp);
WHILE (#iter <= #iterMax)
BEGIN
SET #psubject = 'HIIII'; /*this is in HTML example */
SET #pbody = 'You got one email';
IF ((SELECT COUNT(*)
FROM [Table_B]
WHERE R_Id = (SELECT Id FROM #temp WHERE RecId = #iter)
AND [Mail1_Flag] = 'Y'
AND [Mail2_Flag] = 'Y') = 1)
BEGIN
IF ((SELECT COUNT(*)
FROM [Table_A] R
JOIN [Table_B] T ON R.Id = T.r_Id
WHERE R_Id = (SELECT Id FROM #temp WHERE RecId = #iter)
AND R.[Date] <= (DATEADD(DAY, -1, GETDATE()))
AND T.[Sent_Flag] IS NULL) = 1)
BEGIN
SET #pSendTo = N'ABC#gmail.com';
EXEC msdb.dbo.sp_send_dbmail #profile_name = #pProfile,
#body = #pbody,
#subject = #psubject,
#recipients = #pSendTo,
#body_format = 'HTML';
END;
UPDATE [Table_B]
SET [Sent_Flag] = 'Y'
WHERE [Id] IN (SELECT Id FROM #temp WHERE RecId = #iter);
END;
END;
SET #iter = #iter + 1;
END;
END;
IF OBJECT_ID('tempd..#temp') IS NOT NULL
DROP TABLE #temp;
END;
This program is checking that if date is more than 24 hours then it will send a mail correspondingly. I am able to trigger a mail. But I am getting multiple mails. Like the loop is running infinitely and getting same mail multiple times and the sent_Flag column is initial NULL and after a mail is sent it sholud update to 'Y' but it is also not updating to 'Y' after mail is triggered.
Please help to resolve this issue. Thank you
You are not incrementing the counter inside the loop:
UPDATE [Table_B]
SET [Sent_Flag] = 'Y'
WHERE [Id] IN (SELECT Id FROM #temp WHERE RecId = #iter);
END; --this is the END of the first IF BEGIN
END; --this is the END of the WHILE BEGIN
SET #iter = #iter + 1; --and here you update the counter, which will never be reached
If you don't increment the counter inside the loop, the loop will run infinitely, since the loop condition will always be true.

SQL Server while loop and dynamic SQL

I am trying to execute the dynamic SQL from SQL Server while loop. When the only print statement is executed query prints in the correct format but does not execute dynamic SQL with execute() or SP_EXECUTESQL. Please suggest.
Code:
WHILE( #count > 0 )
BEGIN
SELECT
#minID = MinID,
#maxID = MaxID
FROM
IDRange
WHERE
ID = #count
SET #QueryString = ' UPDATE
SD WITH(TABLOCk)
SET a = S4H.ID
FROM
A (nolock) S4H
INNER JOIN B SD on S4H.col = SD.col AND S4H.col1 = SD.col1
WHERE
SD.ID between ' + convert (varchar,#minID )+' AND '+convert (varchar,#maxID )+' AND
S4H.ID <= SD.ID AND
SD.ID <= S4h.ROWID'
SET #count= #count - 1'
print #QueryString
EXECUTE (#QueryString)
EXECUTE sp_executesql #QueryString, N'#minID INT,#maxID INT', #minID = #minID,#maxID= #maxID
--EXEC SP_EXECUTESQL #QueryString
--SELECT #Rcount= ##Rowcount
SET #count= #count - 1
END
END
There is an open ' at the end of SET #count= #count, remove that.
Use EXEC (#QueryString) to execute it, so it will look this this:
WHILE(#count > 0)
BEGIN
SELECT
#minID = MinID,
#maxID = MaxID
FROM IDRange
WHERE ID = #count;
SET #QueryString = ' UPDATE
SD WITH(TABLOCk)
SET a = S4H.ID
FROM
A (nolock) S4H
INNER JOIN B SD on S4H.col = SD.col AND S4H.col1 = SD.col1
WHERE
SD.ID between '+CONVERT(VARCHAR, #minID)+' AND '+CONVERT(VARCHAR, #maxID)+' AND
S4H.ID <= SD.ID AND
SD.ID <= S4h.ROWID';
PRINT #QueryString;
EXEC (#QueryString);
SET #count = #count - 1;
END;
-- Dynamic Query closing was not proper SET #count= #count - 1' Repeated twice which is not proper
WHILE( #count > 0 )
BEGIN
SELECT #minID = MinID, #maxID = MaxID
FROM IDRange
WHERE ID = #count
SET #QueryString = ' UPDATE
SD WITH(TABLOCk)
SET a = S4H.ID
FROM
A (nolock) S4H
INNER JOIN B SD on S4H.col = SD.col AND S4H.col1 = SD.col1
WHERE
SD.ID BETWEEN ' + convert (varchar,#minID )+' AND '+convert (varchar,#maxID )+' AND
S4H.ID <= SD.ID AND
SD.ID <= S4h.ROWID'
PRINT #QueryString
EXECUTE (#QueryString)
SET #count= #count - 1
END

T-SQL - compare strings char by char

I need to compare two strings character by character using T-SQL. Let's assume i have twor strings like these:
123456789
212456789
Every time the character DO NOT match, I would like to increase the variable #Diff +=1. In this case the first three characters differ. So the #Diff = 3 (0 would be default value).
Thank you for all suggestions.
for columns in table you don't want to use row by row approach, try this one:
with cte(n) as (
select 1
union all
select n + 1 from cte where n < 9
)
select
t.s1, t.s2,
sum(
case
when substring(t.s1, c.n, 1) <> substring(t.s2, c.n, 1) then 1
else 0
end
) as diff
from test as t
cross join cte as c
group by t.s1, t.s2
=>sql fiddle demo
This code should count the differences in input strings and save this number to counter variable and display the result:
declare #var1 nvarchar(MAX)
declare #var2 nvarchar(MAX)
declare #i int
declare #counter int
set #var1 = '123456789'
set #var2 = '212456789'
set #i = LEN(#var1)
set #counter = 0
while #i > 0
begin
if SUBSTRING(#var1, #i, 1) <> SUBSTRING(#var2, #i, 1)
begin
set #counter = #counter + 1
end
set #i = #i - 1
end
select #counter as Value
The below query compares, shows the different characters and bring you the count of differences
Declare #char1 nvarchar(1), #char2 nvarchar(1), #i int = 1, #max int
Declare #string1 nvarchar(max) = '123456789'
, #string2 nvarchar(max) = '212456789'
Declare #diff_table table (pos int , string1 nvarchar(50) , string2 nvarchar(50), Status nvarchar(50))
Set #max = (select case when len(#String1+'x')-1 > len(#string2+'x')-1 then len(#String1+'x')-1 else len(#string2+'x')-1 end)
while #i < #max +1
BEGIN
Select #char1 = SUBSTRING(#string1,#i,1), #char2 = SUBSTRING(#string2,#i,1)
INSERT INTO #diff_table values
(
#i,
case when UNICODE(#char1) is null then '' else concat(#char1,' - (',UNICODE(#char1),')') end,
case when UNICODE(#char2) is null then '' else concat(#char2,' - (',UNICODE(#char2),')') end,
case when ISNULL(UNICODE(#char1),0) <> isnull(UNICODE(#char2),0) then 'CHECK' else 'OK' END
)
set #i+=1
END
Select * from #diff_table
Declare #diff int = (Select count(*) from #diff_table where Status = 'Check')
Select #diff 'Difference'
The output will be like this:

How to compare 2 string while executing the query

declare #pid int
declare #mid int
declare #tableName varchar(10)
declare #query nvarchar(1000)
declare #subquery nvarchar(300)
set #pid = 1
set #mid = 2
set #query = 'Select * from '+#tableName+' where'
if(#pid is not null)
begin
set #query = #query+' pid ='+#pid+' and'
end
if(#mid is not null)
begin
set #query = #query+' mid ='+#mid+' and'
end
if #pid and #mid are not null, get added into the query. If #pid and #mid null, I want to remove 'where' from query. Same for 'and' also, if both get selected.
set #subquery = select right('''+#query+''',5)
if(#subquery = 'where')
begin
print #query
-- execute sp_executesql #query
end
but unable to compare those, in if clause. Does I need to execute #subquery. If yes, how to take that value?
if #pid and #mid are not null,get added into the query.
If #pid and #mid null,I want to remove 'where' from query.
both get selected.
I think you are looking for something like this:
WHERE 1 = 1
AND (#mid IS NULL OR mid = #mid )
AND (#pid IS NULL OR pid = #pid)
If #pid and #mid are not NULLs, the the previous WHERE would be:
WHERE 1 = 1
AND mid = #mid
AND pid = #pid
Therefore they get added into the query.
If #pid and #mid are NULLs, then the WHERE clause would become:
WHERE 1 = 1
Therefore it would be like it it doesn't exist.
Note that, I used WHERE 1 = 1 in case that the two #pid and #mid are both NULLs, the query is keep working and doesn't break.

Return value from exec(#sql)

I want get the value from Exec(#sql) and assign to #Rowcount(int)
Here is my query:
'SET #RowCount = (select count(*)
FROM dbo.Comm_Services
WHERE CompanyId = '+cast(#CompanyId as char)+' and '+#condition+')'
On the one hand you could use sp_executesql:
exec sp_executesql N'select #rowcount=count(*) from anytable',
N'#rowcount int output', #rowcount output;
On the other hand you could use a temporary table:
declare #result table ([rowcount] int);
insert into #result ([rowcount])
exec (N'select count(*) from anytable');
declare #rowcount int = (select top (1) [rowcount] from #result);
DECLARE #nReturn int = 0
EXEC #nReturn = Stored Procedure
Was playing with this today... I believe you can also use ##ROWCOUNT, like this:
DECLARE #SQL VARCHAR(50)
DECLARE #Rowcount INT
SET #SQL = 'SELECT 1 UNION SELECT 2'
EXEC(#SQL)
SET #Rowcount = ##ROWCOUNT
SELECT #Rowcount
Then replace the SELECT 1 UNION SELECT 2 with your actual select without the count. I'd suggest just putting 1 in your select, like this:
SELECT 1
FROM dbo.Comm_Services
WHERE....
....
(as opposed to putting SELECT *)
Hope that helps.
that's my procedure
CREATE PROC sp_count
#CompanyId sysname,
#codition sysname
AS
SET NOCOUNT ON
CREATE TABLE #ctr
( NumRows int )
DECLARE #intCount int
, #vcSQL varchar(255)
SELECT #vcSQL = ' INSERT #ctr FROM dbo.Comm_Services
WHERE CompanyId = '+#CompanyId+' and '+#condition+')'
EXEC (#vcSQL)
IF ##ERROR = 0
BEGIN
SELECT #intCount = NumRows
FROM #ctr
DROP TABLE #ctr
RETURN #intCount
END
ELSE
BEGIN
DROP TABLE #ctr
RETURN -1
END
GO
If i understand you correctly, (i probably don't)
'SELECT #RowCount = COUNT(*)
FROM dbo.Comm_Services
WHERE CompanyId = ' + CAST(#CompanyId AS CHAR) + '
AND ' + #condition