How to use if condition with dynamic SQL - sql

I want to put if condition for following query but getting error
ALTER PROCEDURE [dbo].[GetExternalDocumentHistory]
#reoid int,
#spType VARCHAR(50),
#maximumRows INT = 0,
#startRowIndex INT = 0,
#recordCount INT OUTPUT
AS BEGIN
DECLARE #data TABLE(
id INT IDENTITY(1,1),
property_address NVARCHAR(250),
property_id INT )
INSERT #data( property_address, property_id )
IF( #spType = 'ED' )
BEGIN
SELECT property_address, property_id
FROM external_documents_history as edu
WHERE edu.property_id = #reoid
END;
IF (#spType = 'GD' )
BEGIN
SELECT property_address, property_id
FROM external_documents_history as edu
WHERE edu.page_type = 'GD'
END;
SELECT #recordCount = COUNT(*) FROM #data
IF #maximumRows = 0
BEGIN
SET #startRowIndex = 0
SET #maximumRows = #recordCount
END
SELECT * FROM #data
WHERE id BETWEEN #startRowIndex + 1 AND #startRowIndex + #maximumRows
ORDER BY id
END;
What is the issue with the above query ?

Besides #Alex's two conditional INSERTs (the best way I think), here's a variation on #Sorpigals's answer, without the CASE::
INSERT INTO #data( property_address, property_id )
SELECT property_address
, property_id
FROM external_documents_history as edu
WHERE ( #spType = 'ED' AND edu.property_id = #reoid )
OR ( #spType = 'GD' AND edu.page_type = 'GD' )

You cannot use an IF after the INSERT statement , the simplest option is to restate the insert for all possible conditions;
IF (#spType = 'ED') BEGIN
INSERT #data(property_address, property_id)
SELECT property_address, property_id FROM external_documents_history as edu WHERE edu.property_id = #reoid
END
You can also skip SELECT #recordCount = COUNT(*) FROM #data and use ##ROWCOUNT

Use a case statement in your where clause, e.g.
DECLARE #data TABLE(
id INT IDENTITY(1,1),
property_address NVARCHAR(250),
property_id INT )
INSERT INTO #data( property_address, property_id )
select property_address, property_id FROM external_documents_history as edu
where
case when #spType = 'ED' and edu.property_id = #reoid then 1
case when #spType = 'GD' and edu.page_type = 'GD' then 1
else 0
end = 1
;
SELECT #recordCount = COUNT(*) FROM #data
IF #maximumRows = 0
BEGIN
SET #startRowIndex = 0
SET #maximumRows = #recordCount
END
SELECT * FROM #data
WHERE id BETWEEN #startRowIndex + 1 AND #startRowIndex + #maximumRows
ORDER BY id
END;

For one thing this is not correct:
INSERT #data( property_address, property_id )
Should be:
INSERT INTO table_name
VALUES (value1, value2, value3,...)
And being that this is before your if statement that is probably why your query analyzer / management studio is complaining about the if.

If you are trying a dynamic INSERT INTO Table SELECT A, B, C FROM OtherTableDynamically you will need to prepare the entire statement and use sp_executesql.

Related

SQL While Loop Insert with values from another table

I am trying to create a SQL While loop that will update a temp table with values from another table. Values from the other table:
477286
560565
499330
391827
127375
526354
501736
357359
410433
500946
261297
377667
135931
235691
247239
143672
548752
471945
...
Wrote the following, however, it only inserts the last value multiple times over.
Here is the code:
USE Reports
GO
CREATE TABLE #TempTable (CreatedByID int, LastUpdatedByID int, ID int,
AlertDE int, Alert char(50), StartDTTM datetime, EndDTTM datetime,
IsInactiveFLAG char(1),AlertDetails char(1));
DECLARE #numrows INT
SELECT #numrows = COUNT(*) FROM [Reports].[dbo].[Eligible]
DECLARE #id int
DECLARE #LoopCount INT = 1
DECLARE #count int = #numrows
SELECT #id = [id] FROM [Reports].[dbo].[Eligible]
WHILE (#LoopCount <= #count)
BEGIN
INSERT INTO #TempTable (CreatedByID, LastUpdatedByID, ID, AlertDE, Alert, StartDTTM, EndDTTM, IsInactiveFLAG,AlertDetails)
VALUES (52,52,#id,0,'Eligible',CURRENT_TIMESTAMP,'1900-01-01
00:00:00.000','N','')
SET #LoopCount = #LoopCount + 1
END
SELECT * FROM #TempTable
DROP TABLE #TempTable
I am assuming I have to tell it to loop through the values in the other table somehow but I am not positive if that is the right approach or if in general I am taking the long way around the bus.
Why are you using a loop? You can do this with an insert . . . select statement:
INSERT INTO #TempTable (CreatedByID, LastUpdatedByID, ID, AlertDE, Alert, StartDTTM, EndDTTM, IsInactiveFLAG, AlertDetails)
SELECT 52, 52, e.id, 0, 'Eligible', CURRENT_TIMESTAMP, '1900-01-01 00:00:00.000', 'N', ''
FROM [Reports].[dbo].[Eligible] e ;
See eg https://www.w3schools.com/sql/sql_insert_into_select.asp for more info.
GMR, I found a way to accomplish my need which is similar to yours. Hopefully this will help you too.
DECLARE
#LoopId int
,#TheOrderNumber varchar(20)
DECLARE #CheckThisItem TABLE
(
LoopId int not null identity(1,1)
,TheOrderNumber varchar(20) not null
)
INSERT #CheckThisItem
SELECT Order_Number AS TheOrderNumber
FROM [dbo].[Table_Storing_Order_Number] ORDER BY Order_Number ASC
SET #LoopId = ##rowcount
WHILE #LoopId > 0
BEGIN
SELECT #TheOrderNumber = TheOrderNumber
FROM #CheckThisItem
WHERE LoopId = #LoopId
-- Start inserting record pulled for while loop
INSERT [dbo].[The_Destination_Table]
SELECT TOP (1)
A, B, C, D
FROM [dbo].[Source_Table] ST
WHERE
ST.Order_Number = #TheOrderNumber
-- Set number to reduce loop counter
SET #LoopId = #LoopId - 1
END;

declaring multiple columns in a count value

I am trying to define multiple count values for a counter and corresponding value. Here is my code:
DECLARE #RequestDate AS DATE = '2017-04-20'
;
DECLARE #POCounter INT;
DECLARE #POMax INT;
DECLARE #NewDate DATE;
SET #POCounter = 0;
SET #POMax =
(
SELECT
CUSTOMERPONUMBER,
(
SELECT
COUNT(CUSTOMERPONUMBER)
FROM DailyOpenOrders$
WHERE
RequestDate < #RequestDate
)
FROM DailyOpenOrders$
WHERE
RequestDate < #RequestDate
GROUP BY
CUSTOMERPONUMBER
)
The #POMax counter is to help me update the date that many times for a specific customerPO. I intend to increase the POCounter in a loop until it reaches the #POmax counter for each customerPOnumber.
Am i doing this wrong? can someone help?
#POMax is a scalar variable and can only hold one value at a time.
If you want to hold a collection of values, a table variable is a good tool for that:
DECLARE #MyTable TABLE
(
ID int PRIMARY KEY IDENTITY(1,1),
CustomerNumber varchar(50),
[TheCount] int
)
INSERT INTO #MyTable(CustomerNumber, [TheCount])
SELECT CustomerNumber, COUNT(*)
FROM SomeTable
GROUP BY CustomerNumber
Now you can loop over #MyTable, and for each CustomerNumber, loop from 1 to TheCount...
DECLARE #MyID int
SET #MyID = (SELECT MIN(ID) FROM #MyTable)
WHILE #MyID is not null
BEGIN
SELECT * FROM #MyTable WHERE ID = #MyID
SET #MyID = (SELECT MIN(ID) FROM #MyTable WHERE #MyID < ID)
END

dynamic alias in sql server

I want query field with different alias in stored procedure
select COUNT(EmpCode) as CountEmp+#para
result shoud be
CountEmp1
45
CountEmp2
54
CountEmp1
76
Query loop in c# code:
select COUNT(EmpCode) where something = #something as CountEmp+#para
Approach without dynamic SQL:
--I create temp table for demonstration
DECLARE #some_table TABLE (
Something int,
EmpCode INT
)
INSERT INTO #some_table (Something, EmpCode)
VALUES (1, 10),(1, 22),(1, 12),(2, 12),(2, 30),(3, 65),(3, 15),(3, 11),(3, 5)
--Declare parameter we want to search
DECLARE #param int = 1
--Query
--In cte we select what we need based on parameter
;WITH cte AS (
SELECT 'CountEmp'+CAST(#param as nvarchar(10)) as SomeThing,
CAST(COUNT(EmpCode) as nvarchar(10)) as EmpCodeCount,
ROW_NUMBER() OVER (ORDER BY SomeThing ) as rn
FROM #some_table
WHERE SomeThing = #param
GROUP BY SomeThing
)
--And here comes UNION
SELECT SomeThing as Result
FROM (
SELECT SomeThing,rn
FROM cte
UNION ALL
SELECT EmpCodeCount ,rn
FROM cte
) as t
ORDER BY rn, SomeThing DESC
Output:
Result
------------------
CountEmp1
3
(2 row(s) affected)
Please try to make use of below code. Its working fine with SQL Server 2012.
IF OBJECT_ID ('temp..#Mytable') IS NOT NULL
CREATE TABLE #Mytable (ID INT IDENTITY (1,1),EmpCode INT)
DECLARE #max int ,#count int
SET #max =0;
DECLARE #str varchar(10)
INSERT #Mytable
(EmpCode)
VALUES
(10),
(45),
(35),
(63),
(56),
(65)
SET #count = (SELECT COUNT (ID) FROM #Mytable )
WHILE #count > #max
BEGIN
SET #max = #max+1
SET #str = CONVERT(varchar(10),#max)
EXEC('SELECT EmpCode AS Empcode'+#str+ ' FROM #Mytable WHERE ID = '+#str)
END

Subquery returned more than one value error

I am using the following query, but it is throwing an error. It is working fine for some scenarios, depending on the id, but not for all.
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
Set #NoOfRows = (Select COUNT(*) from #TempT)
While #i <= #NoOfRows
Begin
SET #Voucher_No=( select V_No from #TempT where RowID=#i)
SET #Voucher_Type_No=( select voucher_type_no from #TempT where RowID=#i)
SET #Voucher_Id=( select Voucher_Id from #TempT where RowID=#i)
set #strPartyName=''
set #strPartyName = (Select Party_Name from Cheque_Book where Voucher_No= #Voucher_No and Voucher_Type_No= #Voucher_Type_No and Company_No= #Comp_No and Bank_Account_No= #dbc_Account )
if NULLIF(#strPartyName,'') IS NULL
begin
set #strPartyName =(Select a.account_name from Voucher v inner join account a on v.Account_No = a.account_No where v.Voucher_Id= #Voucher_Id)
Update #TempT Set Party_Name =#strPartyName Where RowID =#i
set #i=#i+1
end
End
Select * from #TempT
Rather than setting variable using sub-query, set variable as shown below.
SELECT #NoOfRows = COUNT(*) FROM #TempT
WHILE #i <= #NoOfRows
BEGIN
SELECT #Voucher_No = V_No FROM #TempT WHERE RowID=#i
SELECT #Voucher_Type_No = voucher_type_no FROM #TempT WHERE RowID=#i
SELECT #Voucher_Id = Voucher_Id FROM #TempT where RowID=#i
SET #strPartyName=''
SELECT #strPartyName = Party_Name FROM Cheque_Book WHERE Voucher_No = #Voucher_No AND Voucher_Type_No = #Voucher_Type_No AND Company_No= #Comp_No AND Bank_Account_No= #dbc_Account
IF NULLIF(#strPartyName,'') IS NULL
BEGIN
SELECT #strPartyName = a.account_name FROM Voucher v INNER JOIN account a ON v.Account_No = a.account_No WHERE v.Voucher_Id= #Voucher_Id
UPDATE #TempT SET Party_Name = #strPartyName WHERE RowID = #i
SET #i = #i + 1
END
END
SELECT * FROM #TempT
Its show that your sub-query return more than one value.
You have to modify your sub-query with TOP keyword or give filter (where condition and order by ) more which return only one value.
While #i <= #NoOfRows
Begin
SET #Voucher_No=( select top 1 V_No from #TempT where RowID=#i)
SET #Voucher_Type_No=( select top 1 voucher_type_no from #TempT where RowID=#i)
SET #Voucher_Id=( select top1 Voucher_Id from #TempT where RowID=#i)
......
END
To resolve the problem, you just only run the actual select query in while loop which gives the result of more than 2 value like
While #i <= #NoOfRows
Begin
--SET #Voucher_No=(
select V_No from #TempT where RowID=#i --)
--SET #Voucher_Type_No=(
select voucher_type_no from #TempT where RowID=#i --)
--SET #Voucher_Id=(
select Voucher_Id from #TempT where RowID=#i --)
......
END
UPDATED
This is sample data to understand what happened with you and how to resolve it.
declare #department table (deptid int, name varchar(50))
declare #emp table (id int, name varchar(50), deptid int)
insert into #department values (1,'d1'), (2,'d2'),(3,'d3'),(4,'d4')
insert into #emp values(1,'ajay',1), (2,'ajay1',1),(3,'ajay3' ,2),(4,'ajay4' ,3),(5,'ajay5' ,4)
select * from #department where deptid = 1
/* suppose your sub-query like */
--1. this give result
select * from #department where deptid = (select deptid from #emp where id = 1)
--2. this give result, but may be get wrong result as it take top 1.
select * from #department where deptid = (select top 1 deptid from #emp )
--3. this give error same you have
select * from #department where deptid = (select deptid from #emp)
--to resolve the above error, just uncomment below sub-query.
--select deptid from #emp
I see answers here for the issue where the following queries fail because their subqueries return multiple values:
SET #Voucher_No = (SELECT [V_No] FROM #TempT WHERE [RowID] = #i);
SET #Voucher_Type_No = (SELECT [voucher_type_no] FROM #TempT WHERE [RowID] = #i);
SET #Voucher_Id = (SELECT [Voucher_Id] FROM #TempT WHERE [RowID] = #i);
There are mainly two proposed solutions in those answers:
SET #Variable = (SELECT TOP (1) [Field] FROM [Table] WHERE ...);, or
SELECT #Variable = [Field] FROM [Table] WHERE ...);.
To my surprise, the second approach is considered to be the preferred approach. There are a few important things to consider, however.
First: if the SELECT-query returns multiple results, the value of #Variable will become the last retrieved value from the query's result set. This has to be regarded when an ORDER BY clause is specified.
So the query below will return 5 instead of 1:
DECLARE #TempTable TABLE ([ID] INT);
INSERT INTO #TempTable VALUES (1), (3), (2), (5), (4);
DECLARE #Variable INT = 42;
SELECT #Variable = [ID] FROM #TempTable ORDER BY [ID];
SELECT #Variable AS [#Variable];
Second: if #Variable already contains a value and the SELECT query does not produce any results (0 rows), the value of #Variable remains unchanged!
So the query below will produce result 42 instead of NULL:
DECLARE #TempTable TABLE ([ID] INT);
INSERT INTO #TempTable VALUES (1), (3), (2), (5), (4);
DECLARE #Variable INT = 42;
SELECT #Variable = [ID] FROM #TempTable WHERE [ID] = 6;
SELECT #Variable AS [#Variable];
For all these reasons, my personal preference lies with the SET #Variable = (SELECT TOP (1) ...) approach.

TSQL - While in While code

Can someone please tell me why this wont work. I want to loop inside a loop .....
BEGIN
SET NOCOUNT ON;
Declare #TempLocations Table (PK int Identity(1,1) not null Primary key, LocationID Int)
Declare #TempItems Table (PK1 int Identity(1,1) not null Primary key, ItemID int)
Declare #TempTable Table (ID Int Identity(1,1), LocationID int, ItemID int)
Declare #MaxLocationID int,
#MaxItemID Int,
#LocationID int,
#ItemID int
-- Load "Can be sold from" Locations into Temp Table
Insert Into #TempLocations (LocationID)
Select LocationID from WMS.Locations
Where CanBeSoldFrom = 'Checked'
Set #MaxItemID = (Select MAX(PK1) From #TempItems)
Set #LocationID = 1
-- Load "IsActive" Items into Temp Table
Insert Into #TempItems (ItemID)
Select ItemID from IMS.ItemDetails
Where IsActive = 'Checked'
Set #MaxLocationID = (Select MAX(PK) From #TempLocations)
Set #ItemID = 1
--Main Code
While #LocationID <= #MaxLocationID
Begin
While #ItemID <= #MaxItemID
Begin
Insert into #TempTable (LocationID, ItemID)
Values (#LocationID, #ItemID)
Set #ItemID = #ItemID + 1
end
Set #LocationID = #LocationID + 1
End
Select * from #TempTable
END
The result I am Tryinig to get is this
#tempTable =
LocationID = 1
ItemID = 1
ItemID = 2
ItemID = 3
ItemID = 4
LocationID = 2
ItemID = 1
ItemID = 2
ItemID = 3
ItemID = 4
and so on ......
This shouldn't be done in a procedural code at all. Use pure SQL and let the DB engine do it's job, it will perform much better, and less code = less bugs. I'm not sure I completely understand what results you want, but I think this does it:
select
LocationID,
ItemID
from
(
Select LocationID from WMS.Locations
Where CanBeSoldFrom = 'Checked'
)
cross join
(
Select ItemID from IMS.ItemDetails
Where IsActive = 'Checked'
)
order by
LocationID,
ItemID
Your query selects the #MaxItemID before anything is filled into #TempItems. Therefor #MaxItemID is null. You have to switch the Statements Set #MaxLocationID = (Select MAX(PK) From #TempLocations) and Set #MaxItemID = (Select MAX(PK1) From #TempItems).
I agree with Jeremy though, it would be better to do that with set-based-programming.