Retrieve values for multiple ids given in the order - sql-server

I am having a stored procedure which uses CSV to accept multiple IDs. I want to retrieve the values from the table in the order of the Ids given. The stored procedure I am currently using is
CREATE procedure [dbo].[Proc1]
#Userid VARCHAR(MAX)=NULL
as
begin
set nocount on;
DECLARE #Useridord TABLE (Userid VARCHAR(MAX),Position int identity(1,1));
INSERT INTO #Useridord
SELECT item
FROM [dbo].[Split] (#Userid, ',')
select * from User where User.UserId IN (select TOP 100 Percent Userid from #Useridord ORDER BY Position)
end
GO
What I am trying to do is from csv I am inserting the values into temporary table adding the order value as position. As I use Orderby Position, it is only implemented in the inner select. But the Output is given as the order in the table. I know to use an orderby in the outer select statement but I don't know the correct syntax to execute it. Can anyone help me?

How about using INNER JOIN?
SELECT
u.*
FROM User u
INNER JOIN #Useridord uo
ON uo.Userid = u.UserId
ORDER BY uo.Position

I believe that you should guaranty position inside function like:
create function fnSplit(#users varchar(100), #del char(10))
returns #t table(userid int, pos int) as
begin
insert into #t values(3,1),(2,2),(1,3)
return
end
Then you can join directly on function result like:
Select u.* from users u
join fnSplit('','') s on u.id = s.userid
order by s.pos
Here is fiddle http://sqlfiddle.com/#!6/a8acc/4

Related

How to pass multiple parameter in where condition in SQL

I have a query to get the order details like below:
declare #orderNo nvarchar(10) = '12345'
begin
select * from orderProperty where CorderID =(select id from Corder where orderno = #orderNo)
End
Its working fine for single order.
However, if I have multiple order numbers ( lets say, 3000) ; How can I get all data in a single query - by passing multiple parameters( that is multiple order numbers) into it?
Thanks.
Create a user-defined table type, then declare a parameter as that table type. Then you can pass your orders into that table parameter and use it as you would any other regular table.
-- create user-defined table type
CREATE TYPE [dbo].[ordersUdt] AS TABLE(
[orderNo] nvarchar(10) NULL
)
GO
-- declare table variable as new type
-- insert order records into table variable
declare #records ordersUdt
insert into #records ([orderNo])
values ('12345'),('34567'),('56789')
-- use table variable as you would regular table
select *
from orderProperty op
join Corder c
on op.CorderID = C.id
join #records r
on R.orderNo = r.orderNo
you can use OPENJSON AND CROSS APPLY
declare a list of order as JSON format
declare #orderNoList AS varchar(max) = '[1,2,3]'
and finally, use cross apply
SELECT *
FROM orderProperty OP
INNER JOIN Corder C ON OP.CorderId = C.id
CROSS APPLY (SELECT [value] FROM OPENJSON(#orderNoList) WHERE C.id = [value]) AS O

How to achieve the flow of execution in a Stored Proc and get an table output

How can we achieve the flow of execution in a Stored Proc and get a table output? Is this possible to call DEMO_PROC and get the output of (SELECT DISTINCT * FROM #TEMP_TABLE) mentioned in the proc? Or is there any alternate way by which this can be achieved?
Sample code:
CREATE PROC DEMO_PROC AS
BEGIN
if object_id('Tempdb..#TMP') is not null
drop table #TMP
select
O.ID, O.NAME, O.E_ID, P.PKG_ID
into #TEMP_TABLE
from Order_Table AS O
join
Package_Table AS P on P.ID = O.ID
WHERE P.PKG_NAME IN (1,2)
ALTER TABLE #TEMP_TABLE ADD COL_V1 nvarchar(100);
UPDATE #TEMP_TABLE set COL_V1 = (SELECT assw FROM Order_Table AS O join ELEC_TABLE AS E ON O.E_ID = E.E_ID
where E.E_ID = #TEMP_TABLE.E_ID
and (E.E_DESC LIKE '%U R SUPER, Thanks! in advance%'))
SELECT DISTINCT * FROM #TEMP_TABLE
END
A table name can be passed to the stored procedure and created inside the SP. Then it can be queried in the calling sql. A table name can returned from the SP and queried in the calling sql.

TSQL Where clause based on temp table data

I have a straight forward SQL query that I am working with and trying to figure out the best way to approach the where clause.
Essentially, there are two temp tables created and if there is data in the XML string passed to the stored procedure, those tables are populated.
My where clause needs to check these temp tables for data, and if there is no data, it ignores them like they are not there and fetches all data.
-- Create temp tables to hold our XML filter criteria
DECLARE #users AS TABLE (QID VARCHAR(10))
DECLARE #dls AS TABLE (dlName VARCHAR(50))
-- Insert our XML filters
IF #xml.exist('/root/data/users') > 0
BEGIN
INSERT INTO #users( QID )
SELECT ParamValues.x1.value('QID[1]', 'varchar(10)')
FROM #xml.nodes('/root/data/users/user') AS ParamValues(x1)
END
IF #xml.exist('/root/data/dls') > 0
BEGIN
INSERT INTO #dls( dlName )
SELECT ParamValues.x1.value('dlName[1]', 'varchar(50)')
FROM #xml.nodes('/root/data/dld/dl') AS ParamValues(x1)
END
-- Fetch our document details based on the XML provided
SELECT d.documentID ,
d.sopID ,
d.documentName ,
d.folderLocation ,
d.userGroup ,
d.notes
FROM dbo.Documents AS d
LEFT JOIN dbo.DocumentContacts AS dc
ON dc.documentID = d.documentID
LEFT JOIN dbo.DocumentContactsDLs AS dl
ON dl.documentID = d.documentID
-- How can I make these two logic checks work only if there is data, otherwise, include everything.
WHERE dc.QID IN (SELECT QID FROM #users)
AND dl.DL IN (SELECT dlName FROM #dls)
FOR XML PATH ('data'), ELEMENTS, TYPE, ROOT('root');
In the query above, I am trying to used the data in the temp tables only if there is data in them, otherwise, it needs to act like that where statement isn't there for that specific value and include records regardless.
Example: If only #users had data, it would ignore AND dl.DL IN (SELECT dlName FROM #dls) and get everything, regardless of what was in the DL column on those joined records.
Use NOT EXISTS to check the existence of any record in variable table. Here is one way
WHERE ( dc.QID IN (SELECT QID FROM #users)
OR NOT EXISTS (SELECT 1 FROM #users) )
AND ( dl.DL IN (SELECT dlName FROM #dls)
OR NOT EXISTS (SELECT 1 FROM #dls) )
Try this. But please note that I did not get a chance to test it properly and I believe that you want to check the values in #users first and if there is no record existing in that table, then you want to check with the entries in #dls. Also if there are no entries in both of these tables, then you want to skip both the tables.
DECLARE #fl bit = 0
SELECT #fl = CASE WHEN EXISTS (SELECT 1 FROM #users) THEN
1
WHEN EXISTS (SELECT 1 FROM #dls) THEN
2
ELSE
0
END
WHERE ( (dc.QID IN (SELECT QID FROM #users) AND #fl = 1)
OR
(dl.DL IN (SELECT dlName FROM #dls) AND #fl = 2)
OR (1=1 AND #fl = 0)
)

TSQL infinite loop in cursor when joining temp table only

I have a SP that updates prices in a table using a CURSOR and FETCH NEXT.
The cursor's query is a simple "select', and instead of a WHERE - I'm joining a function who brings all the related User IDs.
Now, due to the fact the my SP updates a lot of different tables (attached is only part of it), and in every update I use the JOIN of the users function - I wanted to save some time, and bring the Users list only once, at the beginning of the SP.
If I join my temp table (#t, which holds the User IDs) I get an infinite loop.
At the end the prices will be infinite.
BUT - If I join the function itself, instead of the temp table that should have exactly the same values in it, everything is fine.
I commented the problematic JOIN.
-- This is my main object, who "holds" a lot of users
DECLARE #DistID INT = 123
DECLARE #t TABLE
(MainDistID int,
DistID int,
UserID int)
INSERT INTO #t
SELECT MainDistID,
DistID,
UserID
FROM [MyScheme].[FnGetAllDistAndUsers] (#DistID)
DECLARE #Bid INT -- Will contain the ID we need to update
DECLARE c CURSOR LOCAL FOR
SELECT ID
FROM BillingDetails AS bd
-- BOTH JOINS SHOULD BE THE SAME:
--JOIN #t AS GUsers -- Infinite loop...
-- ON bd.UserID = GUsers.UserID
JOIN [MyScheme].[FnGetAllDistAndUsers] (#DistID) AS GUsers -- NO infinite loop
ON bd.UserID = GUsers.UserID
OPEN c
FETCH NEXT FROM c
INTO #Bid
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE MyTable
SET Price = Price * 2
WHERE MyTableID = #Bid
FETCH NEXT FROM c
INTO #Bid
END
Thanks!
I think Mitch is right you shouldn't have to use a cursor. When doing updates it is fastest if you join on the primary key, so you could do something like this.
DECLARE #t TABLE (Bid int)
INSERT INTO #t
SELECT bd.ID
FROM [MyScheme].[FnGetAllDistAndUsers] u (#DistID)
INNER JOIN BillingDetails bd
ON u.UserID = bd.UserID
UPDATE mt
SET Price = Price * 2
FROM MyTable mt
INNER JOIN #t t
ON mt.MyTableID = t.Bid

Can I pass multiple rows from a stored procedure query into another query?

In my previous question I asked about storing the result of a query in a variable... now I realize the query can return multiple rows.
I currently have this:
SELECT #UserId = UserId FROM aspnet_Users WHERE UserName = #username
And I want to do something like this:
DELETE FROM some_table WHERE UserId IN ( *the ID list* )
DELETE FROM some_table_2 WHERE UserId IN ( *the ID list* )
My first instinct is to use "GROUP_CONCAT" but apparently that's a MySQL-only feature. There are some ways to make equivalent functionality, but I'm wondering if there is a better way to structure the queries?
SELECT * FROM dbo.aspnet_UsersInRoles
WHERE UserId IN (
SELECT UserId FROM aspnet_Users
WHERE UserName = #username
)
this should do it ..
SELECT
*
FROM
dbo.aspnet_UsersInRoles
WHERE
UserId IN (
SELECT
UserId
FROM
aspnet_Users
WHERE
UserName = #username
)
delete from st
from some_table st
inner join aspnet_Users au
on st.UserId = au.UserId
where /* add additional criteria here to produce "* the ID list *" */
If you want to avoid to repeat subquery you can put its result into a temp table or a table variable. For instance:
/*declare and fill a table variable containing all user ids you need to manipulate*/
declare #t table(userid int)
insert into #t(userid) select UserId from aspnet_Users where UserName=#username
/*delete from some table by using the temp variable*/
delete from st
from some_table st
inner join #t t
on st.userid = t.userid
/*repeat this for some other table*/
delete from st
from some_other_table st
inner join #t t
on st.userid = t.userid
If you want to avoid multiple delete statements and if presence of user ids in some_other_table doesn't make sense if this doesn't exist in the some_table then you can create trigger on some_table:
create trigger x on some_table for delete
as
begin
delete from some_other_table
where userid in (select userid from deleted)
end

Resources