There is several examples that concatenate string dealing with one single table. In my case I have two tables to take into account.
Table A
requestid int PK
Table B
requestid int
documentname varchar(50)
Table A requestid is of course unique, where table B requestid may have multiple lines. Table B can contain multiple relationship with the same requestid from table A. Also some of the Table A requestid might not have any associated records in table B.
I need to extract and join the two tables. Table A contains ~300k lines and table B contains ~140k lines. See the data below to illustrate what I need to achieve.
Table A sample
requestid FieldA FieldB FieldC
1 33 44 22
2 15 23 73
3 26 73 34
Table B sample
requestid documentname
1 firstdoc.doc
1 seconddoc.doc
1 thirddoc.doc
3 onedoc.doc
3 lastdoc.doc
Expected result:
requestid FieldA FieldB FieldC documentname
1 33 44 22 firstdoc.doc, seconddoc.doc, thirddoc.doc
2 15 23 73 NULL
3 26 73 24 onedoc.doc, lastdoc.doc
In my solution it is very important that requestid with no document associated to it are still in the result.
Hope my question is clear, thank you in advance.
This can be easily done with a stuff
See the example below
declare #tableA table (requestid int, fieldA int, fieldB int, fieldC int)
declare #tableB table (requestid int, documentname varchar(50))
insert into #tableA values (1, 33, 44, 22), (2, 15, 23, 73), (3, 26, 73, 34)
insert into #tableB values (1, 'firstdoc.doc'), (1, 'seconddoc.doc'), (1, 'thirddoc.doc'), (3, 'onedoc.doc'), (3, 'lastdoc.doc')
select a.requestid, a.fieldA, a.fieldB, a.fieldC,
stuff(( ( select ',' + b.documentname
from #tableB b
where b.requestid = a.requestid
order by 1
For XML PATH (''))
), 1, 1, '') as docname
from #tableA a
the result is
requestid fieldA fieldB fieldC docname
--------- ------ ------ ------ --------
1 33 44 22 firstdoc.doc,seconddoc.doc,thirddoc.doc
2 15 23 73
3 26 73 34 lastdoc.doc,onedoc.doc
Related
Here is the Table I am working with (Table1):
Customer ID
Month
Amount Paid
ABC123
1
10
ABC123
2
20
ABC123
3
30
ABC123
4
40
ABC999
1
15
ABC999
2
30
This is what I want my new table to look like (Table2):
Customer ID
AmtPaid_M1
AmtPaid_M2
AmtPaid_M3
AmtPaid_M4
ABC123
10
20
0
40
ABC999
15
30
0
0
I want to just have one row per Customer ID that shows how much they paid each month, instead of having the ID repeated for each month. Is there a simple way to do this using joins or case when statements? Thank you!
You can use pivot
Schema and insert statements:
create table Table1(Customer_ID varchar(50), Month int, Amount_Paid int);
insert into Table1 values('ABC123', 1, 10);
insert into Table1 values('ABC123', 2, 20);
insert into Table1 values('ABC123', 3, 30);
insert into Table1 values('ABC123', 4, 40);
insert into Table1 values('ABC999', 1, 15);
insert into Table1 values('ABC999', 2, 30);
Query:
select Customer_Id, [1] AmtPaid_M1,[2]AmtPaid_M2,[3] AmtPaid_M3, [4] AmtPaid_M4 from Table1
pivot
(
max(Amount_Paid) for Month in ([1],[2],[3],[4])
)pvt
Output:
Customer_Id
AmtPaid_M1
AmtPaid_M2
AmtPaid_M3
AmtPaid_M4
ABC123
10
20
30
40
ABC999
15
30
null
null
** Assuming that you are using SQL Server
db<>fiddle here
I would like to know if two tables 'table1' and 'table2' are identical.
I know I could compare every column of both tables in the 'where'-clause
So this would basically show me every Row that is identical.
But what I want to know is which columns are identical. So I think it would be easy to just transpone the tables and compare the results as mentioned before. Column names and order in the tables are both identical as already given.
I made also an example Input and Output scenario:
-------Input---------------
table1
id
col1
col2
col3
1
14
23
45
2
12
21
43
3
12
22
43
4
10
12
41
5
11
23
44
6
13
25
43
table2
id
col1
col2
col3
1
14
20
45
2
12
0
43
3
12
22
43
4
10
30
41
5
11
23
44
6
13
43
----------Output----------------
result
col2
20
0
22
30
23
OR result
???
???
???
???
???
???
???
col2
20
0
22
30
23
OR result
col2
OR result
table1.col2
table2.col2
23
20
21
0
22
22
12
30
23
23
25
OR similar.....
The values of the non identical columns dont matter I just need the column name, but I wouldnt care if values would come along with it. I hope its not too diffcult.
Consifering you really want to receive only the identical columns, you might want to try an approach using unpivot. Following an example:
DECLARE #t1 TABLE(
id int
,col1 int
,col2 int
,col3 int
);
INSERT INTO #t1 VALUES
(1,14,23,45)
,(2,12,21,43)
,(3,12,22,43)
,(4,10,12,41)
,(5,11,23,44)
,(6,13,25,43);
DECLARE #t2 TABLE(
id int
,col1 int
,col2 int
,col3 int
);
INSERT INTO #t2 VALUES
(1,14,20,45)
,(2,12,0,43)
,(3,12,22,43)
,(4,10,30,41)
,(5,11,23,44)
,(6,13,NULL,43);
WITH cte1 AS(
SELECT id, col, val
FROM (SELECT id, col1, col2, col3 FROM #t1) p
UNPIVOT
(val FOR col IN (col1, col2, col3)) as unpvt
),
cte2 AS(
SELECT id, col, val
FROM (SELECT id, col1, col2, col3 FROM #t2) p
UNPIVOT
(val FOR col IN (col1, col2, col3)) as unpvt
)
SELECT DISTINCT c1.id, c1.col, c1.val
FROM cte1 c1
INNER JOIN cte2 c2 ON c2.id = c1.id AND c2.col = c1.col AND c2.val = c1.val
ORDER BY 1, 2
I have an existing database where some logic is made by the front end application.
Now I have to make reports from that database and I'm facing to a proble of missing records which are covered on a record basis in the frontend but have issues in the report
Given the following tables:
create table #T (id int, id1 int, label varchar(50))
create table #T1 (id int, T_id1 int, A int, B int, C int)
With the values:
insert into #T values (10, 1, 'label1'), (10, 2, 'label2'), (10, 3, 'label3'), (10, 15, 'label15'), (10, 16, 'label16'), (20, 100, 'label100'), (20, 101, 'label101')
insert into #T1 values (10, 1, 100, 200, 300), (10, 15, 150, 250, 350), (20, 100, 151, 251, 351), (20, 101, 151, 251, 351)
if I make a report we can see some missing records:
select #T.id, #T.id1, #T1.A, #T1.B, #T1.C
from #T left join #T1 on #T.id1 = #T1.T_id1
result:
id id1 A B C
10 1 100 200 300
10 2 NULL NULL NULL
10 3 NULL NULL NULL
10 15 150 250 350
10 16 NULL NULL NULL
20 100 151 251 351
20 101 151 251 351
Expected result would be:
id id1 A B B
10 1 100 200 300
10 2 100 200 300
10 3 100 200 300
10 15 150 250 350
10 16 150 250 350
20 100 151 251 351
20 101 151 251 351
As you can see here the missing data is filled out of the the first (in id, id1 order) previous existing record for a given id. For a given id there can be any number of "missing" records and for the given id there can be any number of existing records after a not existing ones.
I can do this with a cursor but I'm looking for a solution without cursor
You can use subquery (to find groups with same values) + window function
WITH Grouped AS (
SELECT #T.id, #T.id1, #T1.A, #T1.B, #T1.C,
GroupN = SUM(CASE WHEN #T1.A IS NULL THEN 0 ELSE 1 END) OVER(/* PARTITION BY id ? */ ORDER BY id1 ROWS UNBOUNDED PRECEDING)
FROM #T
LEFT JOIN #T1 ON #T.id1 = #T1.T_id1
)
SELECT Grouped.id, Grouped.id1,
A = MAX(A) OVER(PARTITION BY GroupN),
B = MAX(B) OVER(PARTITION BY GroupN),
C = MAX(C) OVER(PARTITION BY GroupN)
FROM Grouped
You can use below sql for thedesired output:
with cte (id, id1, A, B, C)
as
(
select #T.id, #T.id1, #T1.A, #T1.B, #T1.C
from #T left join #T1 on #T.id1 = #T1.T_id1
)
select cte.id, cte.id1,
coalesce(cte.A,TT.A) A,
coalesce(cte.B,TT.B) B,
coalesce(cte.C,TT.C) C
from cte
left join
(
select p.id1,max(q.id1) id1_max
from cte p
inner join cte q on p.id1 > q.id1 and p.a is null and q.a is not null
group by p.id1
) T on cte.id1 = T.id1
left join cte TT on T.id1_max = TT.id1
I have two tables Q and A,
records are A are
QID UserID Value
1 100 A
2 100 B
3 100 C
1 101 AA
2 101 BB
3 101 CC
1 102 AAA
2 102 BBB
As you can see, there is no record for user 102 for QID 3. There is this another table Q.
QID Value
1 Name
2 Email
3 Site
What I want is, for each user, weather they have answered a question or not (that is, weather a entry exits in A table or not) I want all questions for all users and their answers. Something like this.
QID QValue UserID Value
1 Name 100 A
2 Email 100 B
3 Site 100 C
1 Name 101 AA
2 Email 101 BB
3 Site 101 CC
1 Name 102 AAA
2 Email 102 BBB
What the problem is one row is missing from the desired output, and that is
3 Site 102 NULL
Because for user 102 there is no entry in A table. I tried LEFT JOIN, but obviously it won't give the desired result as all the left table are already there. And INNER JOIN doesn't works either.
It is also complete possible for answers table (table A) to have data like this
QID QValue UserID Value
1 Name 100 A
2 Email 101 BB
3 Site 102 CCC
Say, all users just have filled in one record, in this case desired output is something like this
QID QValue UserID Value
1 Name 100 A
2 Email 100 NULL
3 Site 100 NULL
1 Name 101 NULL
2 Email 101 BB
3 Site 101 NULL
1 Name 102 NULL
2 Email 102 NULL
3 Email 102 CCC
If I do a LEFT JOIN on QID it doesn't works. Please suggest what should be done.
Try this:
declare #A table(QID int, UserID int, Value varchar(10))
declare #Q table(QID int, Value varchar(10))
insert into #A values (1, 100, 'A')
insert into #A values (2, 100, 'B')
insert into #A values (3, 100, 'C')
insert into #A values (1, 101, 'AA')
insert into #A values (2, 101, 'BB')
insert into #A values (3, 101, 'CC')
insert into #A values (1, 102, 'AAA')
insert into #A values (2, 102, 'BBB')
insert into #Q values (1, 'Name')
insert into #Q values (2, 'Email')
insert into #Q values (3, 'Site')
select
U.UserID,
Q.QID,
Q.Value as QValue,
A.Value
from
(select distinct UserID from #A) U -- all Users
cross join #Q Q -- all Questions
left outer join #A A on A.UserID = U.UserID and A.QID = Q.QID
So basically you do a cross join between all questions and all users first to get all combinations. Then you take this result and do a left join with all the answers. Missing answers will have NULL values in the Value (the real answer) field.
I have a table holding email addresses where some people have more than one email address listed. I want to query the table to only pull a single email address per Individual.
Columns are:
ID
IndividualID
Email
Example data:
1 34 dave#gmail.com
2 65 bob#gmail.com
3 34 david#gmail.com
What I want as the result set is (Only pull one row per IndividualID):
1 34 dave#gmail.com
2 65 bob#gmail.com
Use ROW_NUMBER()
DECLARE #sample TABLE (
ID int,
IndividualID int,
Email varchar(128)
)
INSERT INTO #sample
VALUES
(1, 34, 'dave#gmail.com'),
(2, 65, 'bob#gmail.com'),
(3, 34, 'david#gmail.com')
SELECT *
FROM (
SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY IndividualId ORDER BY ID)
FROM #sample
) AS data
WHERE RN = 1