How can i select multiple row and cascade them? - sql

Let's say I have three tables:
table1 fields:
memberid | name
table2 fields:
interestId | interestName
table3 (used to make a relation between member and interest) fields:
memberid | interestId
and now I know I can user inner join to select one member's all interests.
But how can I cascade all the interests in a single row???
For example, I can select this result:
memberid name interstId interestName
1 dennis 1 play basketball
1 dennis 2 music
1 dennis 3 moive
but the result i want to get is:
memberid name interests
1 dennis play basketball, music, moive
How can I write the SQL query?
Thanks in advance!

In SQL Server 2005 onwards, You can use XML Path() to concatenate values. It appears to be very performant too.
EDIT : Have tested the following and works
SELECT
t1.memberid,
t1.[name],
ISNULL(STUFF(
(
SELECT
', ' + t2.interestName
FROM
table2 t2
INNER JOIN
table3 t3
ON
t2.interestId = t3.interestId
WHERE
t3.memberid = t1.memberid
FOR XML PATH('')
), 1, 2, ''
), 'None') As interests
FROM
table1 t1
GROUP BY
t1.memberid,
t1.[name]
Example code:
DECLARE #table1 TABLE ( memberid INT IDENTITY(1,1), name VARCHAR(25) )
INSERT INTO #table1 VALUES('dennis');
INSERT INTO #table1 VALUES('mary');
INSERT INTO #table1 VALUES('bill');
DECLARE #table2 TABLE ( interestId INT IDENTITY(1,1), interestName VARCHAR(25) )
INSERT INTO #table2 VALUES('play basketball');
INSERT INTO #table2 VALUES('music');
INSERT INTO #table2 VALUES('movie');
INSERT INTO #table2 VALUES('play hockey');
INSERT INTO #table2 VALUES('wine tasting');
INSERT INTO #table2 VALUES('cheese rolling');
DECLARE #table3 TABLE ( memberid INT, interestId INT )
INSERT INTO #table3 VALUES(1,1);
INSERT INTO #table3 VALUES(1,2);
INSERT INTO #table3 VALUES(1,3);
INSERT INTO #table3 VALUES(2,2);
INSERT INTO #table3 VALUES(2,4);
INSERT INTO #table3 VALUES(2,6);
INSERT INTO #table3 VALUES(3,1);
INSERT INTO #table3 VALUES(3,5);
INSERT INTO #table3 VALUES(3,6);
SELECT
t1.memberid,
t1.[name],
ISNULL(STUFF(
(
SELECT
', ' + t2.interestName
FROM
#table2 t2
INNER JOIN
#table3 t3
ON
t2.interestId = t3.interestId
WHERE
t3.memberid = t1.memberid
FOR XML PATH('')
), 1, 2, ''
), 'None') As interests
FROM
#table1 t1
GROUP BY
t1.memberid,
t1.[name]
Results
memberid name interests
----------- -----------------------------------------------------------------------
1 dennis play basketball, music, movie
2 mary music, play hockey, cheese rolling
3 bill play basketball, wine tasting, cheese rolling

It depends on the DB you are using. Take a look at this question: Show a one to many relationship as 2 columns - 1 unique row (ID & comma separated list)

since you didn't specify your database, I can advice to take a look at left (right) joins.

http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
GROUP_CONCAT
just saw the comment on the dbms system, but it would work with mysql.

SELECT t1.memberid, t1.name,
STUFF(
( SELECT ', ' + interestName
FROM table2 t2
inner join table3 as t3
on t2.interestId = t3.interestId and t3.memberid = t1.memberid
FOR XML PATH('') //use to merge the interests
), 1, 2, ''
) As interests
FROM table1
This works

Depends on particular database. Maybe it will help you (using T-SQL and MS SQL Server) for a known memberid:
declare #result varchar(8000)
set #result = ''
declare #memberid int
set #memberid = 1
select #result = str(#memberid) + ' ' + (select name from table1 where memberid = #memberid) + ' '
select #result = #result + str(interestid) + ' ' + interest
from
(
select table2.interestid, table2.interestname
from table3
inner join table2 on table2.interestid = table3.interestid
where table3.memberid = #memberid
) t1
select left(#result, LEN(#result) - 1)

Related

Match the codes and copy columns

I am working in SQL Server 2008. I have 2 tables Table1 & Table2.
Table1 has columns
SchoolCode, District, Type, SchoolName
and Table2 has columns
SchoolCode1, District1, Type1, SchoolName1
SchoolCode columns in both tables have the same codes like "1234"; code is the same in both schoolcode columns.
Now I want to copy the District, Type and SchoolName column values from Table1 to Table2 if SchoolCode in both tables is same.
I think the query will use join but I don't know how it works. Any help on how I can do this task?
Maybe use an update statement in join if by copying over you mean updating rows
update t2
set
District1= District,
Type1= Type,
SchoolName1= SchoolName
from Table1 t1
join
Table2 t2
on t1.SchoolCode=t2.SchoolCode1
I could give you a little bit of idea. here is it:
Insert into table2 (District1, Type1, SchoolName1)
SELECT District, Type, SchoolName
FROM table1
where table1.Schoolcode=table2.Schoolcode1
You have to use Inner join to update data from table 1 to table 2, Inner join will join values that are equal. . To learn more about joins, I highly recommend you to read the below article
SQLServer Joins Explained - W3Schools
Please refer the below code, for the convenience I have used the temporary tables..
DECLARE #Table1 TABLE
(
SchoolCode INT,
District VARCHAR(MAX),
Type VARCHAR(MAX),
SchoolName VARCHAR(MAX)
)
DECLARE #Table2 TABLE
(
SchoolCode1 INT,
District1 VARCHAR(MAX),
Type1 VARCHAR(MAX),
SchoolName1 VARCHAR(MAX)
)
INSERT INTO #Table1
( SchoolCode ,District , Type , SchoolName
)
VALUES ( 1 ,'DIS1' ,'X' ,'A'),
( 2 ,'DIS2' ,'Y' ,'B'),
( 3 ,'DIS3' ,'Z' ,'C'),
( 4 ,'DIS4' ,'D' ,'D'),
( 5 ,'DIS5' ,'K' ,'E')
INSERT INTO #Table2
( SchoolCode1 ,District1 , Type1 , SchoolName1
)
VALUES ( 1 ,'DIS1' ,'X' ,'A'),
( 2 ,NULL ,'Z' ,NULL),
( 3 ,'DIS3' ,'Z' ,'C'),
( 4 ,NULL ,'Z' ,'S'),
( 5 ,'DIS5' ,'K' ,'E')
--BEFORE
SELECT * FROM #Table1
SELECT * FROM #Table2
--Logic UPDATE Table 2
UPDATE t2 SET t2.District1 = t1.District,
t2.Type1 = t1.Type,
t2.SchoolName1 = t1.SchoolName
FROM #Table1 t1
INNER JOIN #Table2 t2 ON t1.SchoolCode = t2.SchoolCode1
-- End Logic UPDATE Table 2
--AFTER
SELECT * FROM #Table1
SELECT * FROM #Table2
You can join tables in an UPDATE statement.
Note, I have aliased the tables, table1 and table2 as t1 and t2 respectively.
This is what I did:
create table Table1
(SchoolCode varchar(50),
District varchar(50),[Type] varchar(50),SchoolName varchar(50))
go
create table Table2
(SchoolCode1 varchar(50), District1 varchar(50),[Type1] varchar(50),SchoolName1 varchar(50))
go
insert into table1 values ('1234','District1','High','Cool School')
insert into table1 values ('2222','District2','Lower','Leafy School')
insert into table2 (SchoolCode1) values ('1234')
go
update t2
set District1 = District,
Type1 = [Type],
SchoolName1 = SchoolName
from table1 t1
join table2 t2
on t2.SchoolCode1 = t1.SchoolCode
go
select * from table2
go

Insert to table based on another table if doesn’t exist

From doing a bit of research it seems it’s not possible to do an insert with a where clause?
I have a table I want to import into another table where specific record criteria doesn’t already exist. How would I go about this ?
E.g pseudo code -
insert into table b (select * from table a) where not exists tableb.column1 = tablea.column1 and tableb.column2 = tablea.column2
Could this potentially be done with a Join ?
You can insert using INSERT INTO.. SELECT with NOT EXISTS.
Query
insert into [TableB]
select * from [TableA] as [t1] -- [TableA] and [TableB] structure should be same.
where not exists(
select 1 from [TableB] as [t2]
where [t1].[column1] = [t2].[column1]
and [t1].[column2] = [t2].[column2]
);
Or, if the table structure is not same and need to same few columns, then
Query
insert into [TableB]([column1], [column2], ..., [columnN])
select [column1], [column2], ..., [columnN]
from [TableA] as [t1]
where not exists(
select 1 from [TableB] as [t2]
where [t1].[column1] = [t2].[column1]
and [t1].[column2] = [t2].[column2]
);
You can also use LEFT JOIN with IS NULL as below:
INSERT INTO tableb
SELECT a.*
FROM tablea a
LEFT JOIN tableb b ON b.column1 = a.column1
AND b.column2 = a.column2
WHERE b.column1 IS NULL
Referencing table name from INSERT statement in SELECT part will not work, because INSERT is not a query itself, but nothing prevents to query destination table in SELECT, which produces the data set to be inserted.
INSERT INTO tableb (column1, column2)
SELECT column1, column2 FROM tablea
WHERE NOT EXISTS (SELECT * FROM tableb
WHERE tableb.column1 = tablea.column1
AND tabled.column2 = tablea.column2)
Try this :
Via Insert with Select statement with Not Exists
Declare #table1 table(Id int , EmpName varchar(100) )
Declare #table2 table(Id int , EmpName varchar(100) )
Insert into #table1 values (1,'Ajay'), (2, 'Tarak') , (3,'Nirav')
Insert into #table2 values (1,'Ajay')
--Insert into table b (select * from table a) where not exists tableb.column1 = tablea.column1 and tabled.column2 = tablea.column2
INSERT INTO #table2 (id, empname)
select id, empname from #table1
EXCEPT
SELECT id, empname from #table2
Select * from #table1
Select * from #table2
Via merge
Insert into #table2 values (4,'Prakash')
Select * from #table1
Select * from #table2
Declare #Id int , #EmpName varchar(100)
;with data as (select #id as id, #empname as empname from #table1)
merge #table2 t
using data s
on s.id = t.id
and s.empname = t.empname
when not matched by target
then insert (id, empname) values (s.id, s.empname);
Select * from #table1
Select * from #table2

SQL - string combine based on id

Need suggestion to split string in table 1, match its Ids with table 2 and concatenate the values.
Table - 1
Id Tbl1Col
1 2
2 2,4
3
4 6
5 3
Table - 2
Id Tbl2Col
1 E
2 F
3 M
4 U
5 P
6 C
7 N
8 G
Query -
SELECT T2.Tbl2Col
FROM Table1 AS T1
LEFT JOIN Table2 AS T2 WHERE T1.Tbl1Col= T2.Id
WHERE T1.Id = #Id
Now If #Id = 1, Output is F -- works fine
Now If #Id = 2, Output should be FU -- should not be F,U
Yuck! But you can use LIKE:
SELECT T2.Tbl2Col
FROM Table1 T1 LEFT JOIN
Table2 T2
WHERE ',' + T1.Tbl1Col + ',' LIKE '%,' + CAST(T2.Id as VARCHAR(255)) + ',%'
WHERE T1.Id = #Id;
You have a lousy data format, so this cannot make use of indexes. You should really have a separate table, with one row per Table1.id and Table2.id. Such a table is called a junction table or an association table.
create table dbo.Table01 (
Id int
, Col varchar(100)
);
create table dbo.Table02 (
Id int
, Col varchar(100)
);
insert into dbo.Table01 (Id, Col)
values (1, '2'), (2, '2, 4');
insert into dbo.Table02 (Id, Col)
values (1, 'E'), (2, 'F'), (4, 'U');
select
t.Id
, replace(STRING_AGG (t02.Col, ','), ',', '') as StringAgg
from dbo.Table01 t
cross apply string_split (t.Col, ',') as ss
inner join dbo.Table02 t02 on ss.value = t02.Id
group by t.id
Follow the next approach:-
1) Turning a Comma Separated string into individual rows via using CROSS APPLY with XML
2) Join the two tables with left join.
3) Concatenate many rows with same id via using STUFF & FOR XML
4) Use Replace function for removing comma.
Demo:-
declare #MyTable table (id int , Tbl1Col varchar(10))
insert into #MyTable values (1,'2'),(2,'2,4'),(3,''),(4,'6'),(5,'3')
declare #MyTable2 table (id int , Tbl2Col varchar(10))
insert into #MyTable2 values (1,'E'),(2,'F'),(3,'M'),(4,'U'),(5,'P'),(6,'C'),(7,'N'),(8,'G')
select a.id , Tbl2Col
into #TestTable
from
(
SELECT A.id,
Split.a.value('.', 'VARCHAR(100)') AS Tbl1Col
FROM
(
SELECT id,
CAST ('<M>' + REPLACE(Tbl1Col, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM #MyTable
) AS A CROSS APPLY Data.nodes ('/M') AS Split(a) ) a
left join #MyTable2 b
on a.Tbl1Col = b.id
order by a.id
SELECT id, Tbl2Col =
Replace(STUFF((SELECT DISTINCT ', ' + Tbl2Col
FROM #TestTable b
WHERE b.id = a.id
FOR XML PATH('')), 1, 2, ''),',','')
FROM #TestTable a
GROUP BY id
Output:-
1 F
2 F U
3 NULL
4 C
5 M
References:-
Turning a Comma Separated string into individual rows
How to concatenate many rows with same id in sql?
Finally:-
Don't use this approach, and normalize your database instead , just use it as fun/training/trying .... etc code.

Merge multiple rows into single value using update Query

Here is the scenario. I have two tables. I want to merge multiple row value to single value using update query.
DECLARE #Table as Table
(
id int,
name varchar(10)
)
insert into #Table values(1,'a')
insert into #Table values(1,'b')
insert into #Table values(1,'c')
select * from #Table
DECLARE #Table2 as Table
(
id int,
name varchar(10)
)
insert into #Table2 values(1,'a')
update t2 set name = t1.name from #Table2 t2
inner join #Table t1 on t1.id=t2.id
select * from #Table2
I want output from #Table2 as by using update query
id name
----- --------
1 a,b,c
;WITH Table1 AS (
SELECT t.id
, STUFF((SELECT ',' + name
FROM #Table
WHERE id = t.id
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,1,'') AS name
FROM #Table t
GROUP BY t.id)
UPDATE t2
SET t2.name = t1.name
FROM #Table2 t2
INNER JOIN Table1 t1 ON t1.id=t2.id

SQL Cross Tab Function

Hi Dear All My friends,
I want to ask one thing about sql cross tab function.Currently, I am using sql 2008 express version and my table structure is like below.
UserID Str_Value
1 A
1 B
1 C
2 A
2 B
3 D
3 E
I want to get like this .
UserID Str_Value
1 A,B,C
2 A,B
3 D,E
I don't want to use cursor.Is there any function for that one?
Please give me the right way.I really appreciate it.
Thanks.
Best Regards,
Chong
Hope this helps. You can comment ORDER BY T1.Str_Value if not needed and set the nvarchar(500) size as required
SELECT DISTINCT T1.UserId,
Stuff(
(SELECT N', ' + T2.Str_Value
FROM t T2
WHERE T2.userId = T1.userid
ORDER BY T2.Str_Value
FOR XML PATH(''),TYPE).value('text()[1]','nvarchar(500)'),1,2,N'')
AS Str_Value
FROM t T1
SELECT UserId, LEFT(Str_Value, LEN(Str_Value) - 1) AS Str_Value
FROM YourTable AS extern
CROSS APPLY
(
SELECT Str_Value + ','
FROM YourTable AS intern
WHERE extern.UserId = intern.UserId
FOR XML PATH('')
) pre_trimmed (Str_Value)
GROUP BY UserId, Str_Value
Try this:
SELECT DISTINCT
t1.UserID,
Values = SUBSTRING((SELECT ( ', ' + t2.Str_Value)
FROM dbo.Users t2
ORDER BY
t2.Str_Value
FOR XML PATH( '' )
), 3, 4000 )FROM dbo.Users t1
GROUP BY t1.UserID
create table #temp
(
userid int,
str_value varchar(1)
)
insert into #temp values (1, 'A')
insert into #temp values (1, 'B')
insert into #temp values (1, 'C')
insert into #temp values (2, 'A')
insert into #temp values (2, 'B')
insert into #temp values (3, 'D')
insert into #temp values (3, 'E')
select userid, left(x.str_value, len(x.str_value) -1) as str_value
from #temp t
cross apply
(
select str_value + ','
FROM #temp t1
where t.userid = t1.userid
for xml path('')
) x (str_value)
group by userid, x.str_value
drop table #temp