SQL Match multiple rows - sql-server

relationID sessionID_Ref userID_Ref
1 1 1
2 1 2
3 2 1
4 2 3
5 3 1
6 3 2
7 3 3
Okey! I'm building a messaging system with the possibility to send messages to a group of people. But I'm stuck with this SQL query where to find the sessionID depending on what users I send the message to.
For example: If I (userID: 1) send a message to userID 2, the SQL Query should return sessionID: 1
If I send a message to userID 2 and 3, it sould return: sessionID: 3
Can I do this with a single sql query, using MSSQL?

Possibly something like this:
select sessionID_Ref
from tablename
group by sessionID_Ref
having count(distinct userID_Ref) = 2
and min(userID_Ref) = 1
and max(userID_Ref) = 2
Here's a full example:
create table #tablename (
relationID int,
sessionID_Ref int,
userID_Ref int
)
insert into #tablename values(1,1,1)
insert into #tablename values(2,1,2)
insert into #tablename values(3,2,1)
insert into #tablename values(4,2,3)
insert into #tablename values(5,3,1)
insert into #tablename values(6,3,2)
insert into #tablename values(7,3,3)
create table #users (
users int
)
insert into #users values(1)
insert into #users values(3)
select t.sessionID_Ref from #tablename t
inner join #users u on t.userID_Ref = u.users
inner join (
select t.sessionID_Ref
from #tablename t
group by t.sessionID_Ref
having COUNT(t.userID_Ref) = (select COUNT(*) from #users)
) aux on aux.sessionID_Ref = t.sessionID_Ref
group by t.sessionID_Ref
having COUNT(t.userID_Ref) = (select COUNT(*) from #users)
drop table #tablename
drop table #users

SELECT TOP 1 sessionID_Ref
FROM table AS table_2
WHERE (userID_Ref = 28 OR
userID_Ref = 11) AND
((SELECT COUNT(*) AS Expr1
FROM table AS table_1
WHERE (sessionID_Ref = table_2.sessionID_Ref) AND (userID_Ref = 28) OR
(sessionID_Ref = table_2.sessionID_Ref) AND (userID_Ref = 11)) = 2) AND
((SELECT COUNT(*) AS Expr1
FROM table AS table_1
WHERE (sessionID_Ref = table_2.sessionID_Ref)) = 2)
This works, but there must be a faster way....

Related

I need to insert rows in bulk like in 1000's using triggers having different value in one column

Here is the trigger
CREATE TRIGGER [dbo].[Teacher]
ON [dbo].[Teacher]
After INSERT
AS
Declare #fid int, #PR NVARCHAR(MAX),#Mycounter as INT
Select top 1 #fid = eid from human where TypeID = 2
order by NewID()
Select top 1 #PR = Pid from [dbo].[Program] Where Depid = 1
order by NewID()
Set #Mycounter =1
While #Mycounter <5
BEGIN
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID, #fid,#PR,NULL,null from INSERTED
Where eid in (Select eid from human where TypeID = 3)
set #MyCounter = #MyCounter + 1;
END
I need to insert 1000's of rows in HeadofDep table when any row is inserted in Teacher table. I have done by applying looping but all rows that get inserted in HeadofDep table have same #PR. Need it different against each row.
Also need sessionid incremented.
How can I achieve that?
Just, increment the SessionID then and put the other stuff in the loop:
Declare #fid int, #PR NVARCHAR(MAX),#Mycounter as INT
Set #Mycounter =1
While #Mycounter <5
BEGIN
Select top 1 #fid = eid from human where TypeID = 2
order by NewID()
Select top 1 #PR = Pid from [dbo].[Program] Where Depid = 1
order by NewID()
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID, #fid,#PR,NULL,null from INSERTED
Where eid in (Select eid from human where TypeID = 3)
set #MyCounter = #MyCounter + 1;
END
Also, doing such LOOPs in triggers is bad.In this case, you can change 1000 inserts with one like this:
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID + N, #fid,#PR,NULL,null
from INSERTED
CROSS APPLY
(
SELECT TOP (1000) -1+row_number() over(order by t1.number) as N
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) DS
Where eid in (Select eid from human where TypeID = 3)

Multiple select queries execution one after other

I am having six select queries with different where conditions if first select query returns null it should check the next select query and follows. what is the best approach to follow for writing it as stored procedure in SQL server.
You can use ##rowcount
DECLARE #OperatorID INT = 4, #CurrentCalendarView VARCHAR(50) = 'month';
declare #t table (operatorID int, CurrentCalendarView varchar(50));
insert into #t values (2, 'year');
select operatorID - 1, CurrentCalendarView from #t where 1 = 2
if (##ROWCOUNT = 0)
begin
select operatorID + 1, CurrentCalendarView from #t where 1 = 1
end
If I understand your question correctly then you can achieve this like below sample. You can go in this way.
if NOT EXISTS (SELECT TOP(1) 'x' FROM table WHERE id =#myId)
BEGIN
IF NOT EXISTS (SELECT TOP(1) 'x' FROM table2 WHERE id = #myId2)
BEGIN
IF NOT EXISTS (SELECT TOP(1) 'x' FROM table 3 WHERE id = #myID3)
BEGIN
END
END
END

Multiple tables in the where clause SQL

I have 2 tables:-
Table_1
GetID UnitID
1 1,2,3
2 4,5
3 5,6
4 6
Table_2
ID UnitID UserID
1 1 1
1 2 1
1 3 1
1 4 1
1 5 2
1 6 3
I want the 'GetID' based on 'UserID'.
Let me explain you with an example.
For e.g.
I want all the GetID where UserID is 1.
The result set should be 1 and 2. 2 is included because one of the Units of 2 has UserID 1.
I want all the GetID where UserID is 2
The result set should be 2 and 3. 2 is included because one of Units of 2 has UserID 2.
I want to achieve this.
Thank you in Advance.
You can try a query like this:
See live demo
select
distinct userid,getid
from Table_1 t1
join Table_2 t2
on t1.unitId+',' like '%' +cast(t2.unitid as varchar(max))+',%'
and t2.userid=1
The query for this will be relatively ugly, because you made the mistake of storing CSV data in the UnitID column (or maybe someone else did and you are stuck with it).
SELECT DISTINCT
t1.GetID
FROM Table_1 t1
INNER JOIN Table_2 t2
ON ',' + t1.UnitID + ',' LIKE '%,' + CONVERT(varchar(10), t2.UnitID) + ',%'
WHERE
t2.UserID = 1;
Demo
To understand the join trick being used here, for the first row of Table_1 we are comparing ,1,2,3, against other single UnitID values from Table_2, e.g. %,1,%. Hopefully it is clear that my logic would match a single UnitID value in the CSV string in any position, including the first and last.
But a much better long term approach would be to separate those CSV values across separate records. Then, in addition to requiring a much simpler query, you could take advantage of things like indices.
try this:
declare #Table_1 table(GetID INT, UnitId VARCHAR(10))
declare #Table_2 table(ID INT, UnitId INT,UserId INT)
INSERT INTO #Table_1
SELECT 1,'1,2,3'
union
SELECT 2,'4,5'
union
SELECT 3,'5,6'
union
SELECT 4,'6'
INSERT INTO #Table_2
SELECT 1,1,1
union
SELECT 1,2,1
union
SELECT 1,3,1
union
SELECT 1,4,1
union
SELECT 1,5,2
union
SELECT 1,6,3
declare #UserId INT = 2
DECLARE #UnitId VARCHAR(10)
SELECT #UnitId=COALESCE(#UnitId + ',', '') + CAST(UnitId AS VARCHAR(5)) from #Table_2 WHERE UserId=#UserId
select distinct t.GetId
from #Table_1 t
CROSS APPLY [dbo].[Split](UnitId,',') AS AA
CROSS APPLY [dbo].[Split](#UnitId,',') AS BB
WHERE AA.Value=BB.Value
Split Function:
CREATE FUNCTION [dbo].Split(#input AS Varchar(4000) )
RETURNS
#Result TABLE(Value BIGINT)
AS
BEGIN
DECLARE #str VARCHAR(20)
DECLARE #ind Int
IF(#input is not null)
BEGIN
SET #ind = CharIndex(',',#input)
WHILE #ind > 0
BEGIN
SET #str = SUBSTRING(#input,1,#ind-1)
SET #input = SUBSTRING(#input,#ind+1,LEN(#input)-#ind)
INSERT INTO #Result values (#str)
SET #ind = CharIndex(',',#input)
END
SET #str = #input
INSERT INTO #Result values (#str)
END
RETURN
END

Display multiple values from two tables in one row in SQL Server

I have the following two tables
TableA Table B
id bid bname btitle
---- ------------------------------
1 1 john titlejohn
2 1 william titlewilliam
3 1 george titlegeorge
2 bill titlebill
3 kyle titlekyle
3 seb titleseb
I need a query in SQL Server which displays the following output:
id name title
1 john,william,george titlejohn,titlewilliam,titlegeorgw
2 bill titlebill
3 kyle,seb titlekyle,titleseb
Please help.
select id, name = stuff(n.name, 1, 1, ''), title = stuff(t.title, 1, 1, '')
from TableA a
outer apply
(
select ',' + bname
from TableB x
where x.bid = a.id
for xml path('')
) n (name)
outer apply
(
select ',' + btitle
from TableB x
where x.bid = a.id
for xml path('')
) t (title)
Here's one solution. It only handles bname but you can extend it to handle btitle. Concatenating column values for a given key is not a natural thing in SQL so you need a trick to loop through the table extracting each row with same key. The trick is to create a memory table with an identity column (n say) which autoincrements on each insert. You can loop through then, picking n=1, then n=2, etc to build up the string.
create function tbl_join_name( #id int)
returns varchar(max)
as
begin
declare #tbl table (n int identity(1,1), name varchar(max), title varchar(max))
insert #tbl( name, title )
select bname, btitle from TableB where bid = #id
declare #n int = 1, #name varchar(max) = '', #count int = (select count(*) from #tbl)
while #n <= #count begin
set #name = #name + (case #name when '' then '' else ',' end) + (select name from #tbl where n = #n)
set #n = #n + 1
end
return #name
end
go
select id, tbl_join_name(id) as bname --, tbl_join_title(id) as btitle
from TableA
It's not very efficient, though. Tested with Sql Server 2008 R2.
Another way:
SELECT A.id,
STUFF((SELECT ','+bname
FROM TableB B
WHERE B.bid = A.id
FOR XML PATH('')),1,1,'') as name,
STUFF((SELECT ','+btitle
FROM TableB B
WHERE B.bid = A.id
FOR XML PATH('')),1,1,'') as title
FROM TableA A
Output:
id name title
1 john,william,george titlejohn,titlewilliam,titlegeorge
2 bill titlebill
3 kyle,seb titlekyle,titleseb

SQL Server Stored Procedure (Menu System) - Microsoft SQL Server 2005

Suppose - I have the following Table Structure
elementid, parentid, elementtitle, sortorder
160 0 Brand New Tutorial 1
161 160 Brand New Tutorial New Step 1
168 5 Tutorial Topic 1.1 1
171 168 Tutorial Topic 1.1.1 1
172 171 Tutorial Topic 1.1.1.1 1
I need to be able to setup a Stored Procedure that will allow me to Update the Elementid's, Parentid's relationship.
Here is my Normal SQL For Generating the tree:
WITH menu AS
(
SELECT parentid, elementid, elementtitle, sortorder FROM dbo.ta_tutorial_elements WHERE (elementid = #eid)
UNION ALL
SELECT e.parentid, e.elementid, e.elementtitle, e.sortorderFROM dbo.ta_tutorial_elements AS e INNER JOIN menu AS m ON e.parentid = m.elementid
)
SELECT * INTO [#tmpA] FROM menu
I believe it could be possible to use temp tables to copy the table over and then somehow use the identity of the insert into my standard table to start with the elementid and the root parent...however, after that I am pretty much lost on how to recursively udpate all parentid's, elementid's with their relationships...(is it possible in SQL Server?).
I am seeing something like the following:
CREATE PROCEDURE [dbo].[sp_ta_copy_tutorial_by_id]
#eid bigint
AS
SET nocount on
BEGIN
DECLARE #recid bigint
SET #recid = (SELECT IDENT_CURRENT('ta_tutorial_elements'));
WITH menu AS
(
SELECT parentid, elementid, elementtitle, sortorder, userid, createddate FROM dbo.ta_tutorial_elements WHERE (elementid = #eid)
UNION ALL
SELECT e.parentid, e.elementid, e.elementtitle, e.sortorder, e.userid, e.createddate FROM dbo.ta_tutorial_elements AS e INNER JOIN menu AS m ON e.parentid = m.elementid
)
SELECT * INTO [#tmpA] FROM menu
ALTER TABLE [#tmpA]
DROP COLUMN elementid
SELECT * INTO [#tmpB] FROM [#tmpA];
UPDATE b SET b.parentid =
CASE
WHEN b.parentid <> 0
THEN #recid
ELSE 0
END
FROM [#tmpB] as b
INSERT INTO [ta_tutorial_elements] SELECT * FROM [#tmpB]
DROP TABLE [#tmpA]
DROP TABLE [#tmpB]
END
Check out CTEs (common table expressions). You can use a CTE within the context of a stored procedure to yield your menu data after some recursion. Actually it looks like you already have a CTE; the link describes recursion within that context.
CREATE PROCEDURE [dbo].[sp_ta_copy_tutorial_by_id]
#eid bigint
AS
SET nocount on
BEGIN
/***************************************
* CREATE A
***************************************/
SELECT *
INTO #tmpA
FROM ta_tutorial_elements
WHERE elementid IN (SELECT elementid from fn_ta_tutorial_tree_by_element (#EID))
/***************************************
* DUPLICATE RECORDS
***************************************/
DECLARE #CNT INT
SET #CNT = (SELECT max(elementid) FROM ta_tutorial_elements)
INSERT
INTO ta_tutorial_elements (elementtitle, parentid)
SELECT elementtitle, parentid FROM #tmpA
/***************************************
* CREATE B
***************************************/
SELECT *
INTO #tmpB
FROM ta_tutorial_elements
WHERE elementid > #CNT
SELECT bpid.elementid as originalelementid,
brow.elementid as newparentid
INTO #tmpC
FROM #tmpB bpid LEFT OUTER JOIN
#tmpA aeid ON bpid.parentid = aeid.elementid LEFT OUTER JOIN
(
SELECT elementid, ROW_NUMBER () OVER (ORDER BY elementid ASC) as rownum
FROM #tmpA
) arow ON arow.elementid = aeid.elementid LEFT OUTER JOIN
(
SELECT elementid, ROW_NUMBER () OVER (ORDER BY elementid ASC) as rownum
FROM #tmpB
) brow ON brow.rownum = arow.rownum LEFT OUTER JOIN
#tmpB beid ON beid.elementid = brow.elementid
UPDATE #tmpC
SET newparentid = 0
WHERE newparentid IS NULL
UPDATE t2
SET parentid = t1.newparentid
FROM #tmpC t1 LEFT OUTER JOIN
ta_tutorial_elements t2 ON t1.originalelementid = t2.elementid
/***************************************
* TEMP DISPLAY
***************************************/
SELECT * FROM ta_tutorial_elements WHERE elementid > #CNT
DROP TABLE #tmpA
DROP TABLE #tmpB
DROP TABLE #tmpC
END

Resources