SQL inner join and group by to get comma separated values - sql

I have following three tables, from which I would like to get a specific result
TableA
key1 key2
-------------
121 4
131 4
141 5
151 3
161 3
171 6
181 6
191 6
... ...
TableB:
key1 key3
-------------
121 1001
131 1111
141 1111
151 1222
161 1222
171 1234
181 1001
191 1111
... ...
TableC:
key3 key4
-------------
1001 "aa"
1111 "gg"
1222 "hh"
1234 "jj"
... ...
I want a SQL query (which could use inner join) to give me the following result:
key2 key4
-------------------------
3 "hh"
4 "aa", "gg"
5 "gg"
6 "aa", "gg", "jj"
Microsoft SQL Server 2012

You can use string_agg():
select t1.key2, string_agg(t3.key4, ',') key4
from table1 t1
inner join table2 t2 on t2.key1 = t1.key1
inner join table3 t3 on t3.key3 = t1.key3
group by t1.key2

Please try with below SQL query:
SELECT key2, string_agg(key4, ",")
FROM TableA JOIN TableB USING (key1) JOIN TableC USING (key3)
GROUP BY key2

Related

Find rows with no match

I need to compare and identify all IDs that have a mismatch in the codes between the categories, upper and lower case are only examples and I cannot base the join on the category field as they are different.
e.g: ID 1 - cat A, a have the same code but ID 3, cat E and e have a mismatch, same with ID#4.
Edit: sorry - after posting the question, and looking at the answers I have realized that my question was not conveying what I am looking for, and I have mocked up data incorrectly. The Category doesn't always have the same name as uppercase/lowercase letters, this was only meant to be an example.
T1
ID Cat Code
1 A 100
1 a 100
1 B 101
1 b 101
2 C 102
2 D 103
2 d 103
3 E 104
3 e 107
3 F 105
3 g 106
4 I 109
4 i 110
5 ABC 111
5 XYZ 112
5 KLM 123
6 PQR 113
6 STU 113
Desired output:
ID Cat Code
3 E 104
3 e 107
4 I 109
4 i 110
5 ABC 111
5 XYZ 112
5 KLM 123
This answers the original version of the question.
Use exists:
select t1.*
from t1
where exists (select 1
from t1 tt1
where tt1.id = t1.id and
upper(tt1.cat) = upper(t1.cat) and
tt1.cat <> t1.cat and
tt1.code <> t1.code
);
Oracle is case-sensitive by default.
You can use a self join like below to handle this issue:
select t1.*
from tablename t1
inner join tablename t2 on t2.ID = t1.ID and upper(t1.Cat) = upper(t2.Cat)
where t1.Code <> t2.Code

SQL Select Return Rows If Column Contain Value or Null Value Base on Key Columns

It was a bit difficult to describe my requirements based on the title, however I'll post with a table sample and result expectation.
I have a table (lets call it TBL_K) that looks like this:
KEY1 KEY2 VALUE1 VALUE2
abc 123 NULL NULL
abc 123 9999 1111
abc 123 9999 1111
ghd 123 NULL NULL
ghd 123 NULL NULL
tiy 134 4444 NULL
tiy 134 4444 NULL
hhh 981 NULL NULL
I want my Select statement to return the result in:
KEY1 KEY2 VALUE1 VALUE2
abc 123 9999 1111
ghd 123 NULL NULL
tiy 134 4444 NULL
hhh 981 NULL NULL
I have came up with own solution with creating two sub-tables with a left outer join but I want to see if there are other ways of creating this result.
It seems nearly to use max() :
select key1, key2, max(val1), max(val2)
from TBL_K tk
group by key1, key2;
SELECT
A.KEY1,
A.KEY2,
B.VALUE1,
B.VALUE2
FROM
(
SELECT
Z.KEY1,
Z.KEY2,
TRIM(Z.VALUE1) VALUE1,
TRIM(Z.VALUE2) VALUE2
FROM
TBL_K Z
WHERE
TRIM(Z.VALUE1) IS NULL
GROUP BY
Z.KEY1,
Z.KEY2,
Z.VALUE1,Z.VALUE2) A LEFT OUTER JOIN
(
SELECT
Y.KEY1,
Y.KEY2,
TRIM(Y.VALUE1) VALUE1,
TRIM(Y.VALUE2) VALUE2
FROM
TBL_K Y
WHERE
TRIM(Y.VALUE1) IS NOT NULL
GROUP BY
Y.KEY1,
Y.KEY2,
Y.VALUE1,Y.VALUE2) B
ON
(A.KEY1 = B.KEY1
AND A.KEY2 = B.KEY2)

SQL - Several rows into one

There are 12 rows in the table in total. Every unique record contains of 4 rows. I want the result on 3 rows/records in total having 4 Fields/columns each.
Example Input:
TEST
455
688
987
Texter
567
53
878
Julgranar
765
454
989
Exampel output/result:
Column1 Column2 Column3 Column4
TEST 455 688 987
Texter 567 53 878
Julgranar 765 454 989
There are a few ways depending on some data rules that you have not included, but here is one way using what you gave.
SELECT
t1.Field1,
t2.Field2
FROM Table1 t1
LEFT JOIN Table1 t2 ON t1.FK = t2.FK AND t2.Field1 IS NULL
Another way:
SELECT
t1.Field1,
(SELECT Field2 FROM Table2 t2 WHERE t2.FK = t1.FK AND Field1 IS NULL) AS Field2
FROM Table1 t1

Complex SQL issue in DB2

I have a table TABLE_CLIENT_BOOK which contains USER_ID and BOOK_CODE. This table shows which all books are with a particular USER_ID.
USER_ID BOOK_CODE
------------------------------
1 123
1 124
1 567
2 123
2 432
3 432
3 567
-------------------------------
I have another table TABLE_BOOK which contains details about each book.
BOOK_CODE DETAILS
----------------------------------
123 abcd
124 pqrs
432 xyzw
567 lmnop
568 efgh
----------------------------------
I want to write a query between the two tables which will spit out USER_ID and BOOK_CODE where BOOK_CODE column should have the id of all books from TABLE_BOOK which that user doesn't have. For e.g. user 1 doesn't have books 432 and 568, user 2 doesn't have 124, 567 and 568 and user 3 doesn't have 123, 124, 568.
So the result table of the query would be:
USER_ID BOOK_CODE
----------------------------
1 432
1 568
2 124
2 567
2 568
3 123
3 124
3 568
-----------------------------
This report is to advertise the books which user doesn't have.
How do I achieve this in SQL in DB2 9 ?
Thanks for reading!
Do a CROSS JOIN to get all user/book combinations. Use NOT EXISTS to exclude already existing combinations:
select distinct tcb.USER_ID, tb.BOOK_CODE
from TABLE_CLIENT_BOOK tcb
cross join TABLE_BOOK tb
where not exists (select * from TABLE_CLIENT_BOOK tcb2
where tcb2.USER_ID = tcb.USER_ID
and tcb2.BOOK_CODE = tb.BOOK_CODE)
order by tcb.USER_ID, tb.BOOK_CODE
Alternatively, EXCEPT:
select tcb.USER_ID, tb.BOOK_CODE
from TABLE_CLIENT_BOOK tcb
cross join TABLE_BOOK tb
EXCEPT
select USER_ID, BOOK_CODE
from TABLE_CLIENT_BOOK
order by tcb.USER_ID, tb.BOOK_CODE
No DISTINCT needed here. EXCEPT removes the duplicates.
Executes as:
SQL>select distinct tcb.USER_ID, tb.BOOK_CODE
SQL&from TABLE_CLIENT_BOOK tcb
SQL& cross join TABLE_BOOK tb
SQL&where not exists (select * from TABLE_CLIENT_BOOK tcb2
SQL& where tcb2.USER_ID = tcb.USER_ID
SQL& and tcb2.BOOK_CODE = tb.BOOK_CODE)
SQL&order by tcb.USER_ID, tb.BOOK_CODE;
USER_ID BOOK_CODE
=========== ===========
1 432
1 568
2 124
2 567
2 568
3 123
3 124
3 568
8 rows found
SQL>select tcb.USER_ID, tb.BOOK_CODE
SQL&from TABLE_CLIENT_BOOK tcb
SQL& cross join TABLE_BOOK tb
SQL&EXCEPT
SQL&select USER_ID, BOOK_CODE
SQL&from TABLE_CLIENT_BOOK
SQL&order by tcb.USER_ID, tb.BOOK_CODE;
USER_ID BOOK_CODE
=========== ===========
1 432
1 568
2 124
2 567
2 568
3 123
3 124
3 568
8 rows found

SQL display data which is not mapped in another table

I am looking for a query to a result where I can see only userid1 data whose provider is not mapped in Table 2; Here is my table definition and data;
Table 1
userid providerid
1 101
1 104
1 106
1 107
2 102
2 103
2 104
Table 2
providerid
101
102
103
104
105
106
107
108
109
110
query required as per the o/p:-
userid providernotavailable
1 102
1 103
1 105
1 108
1 109
1 110
2 101
2 105
2 106
2 107
2 108
2 109
2 110
You can use the not in operator:
SELECT *
FROM table1
WHERE providerid NOT IN (SELECT providerid FROM table2)
Multiple versions: fist with NOT IN
SELECT table1.*
FROM table1
WHERE table1.providerId NOT IN ( SELECT table2.providerId FROM table2 )
Second with NOT EXISTS:
SELECT table1.*
FROM table1
WHERE NOT EXISTS ( SELECT 1
FROM table2
WHERE table1.providerId = table2.providerId )
This next one is a bit strange: we do a LEFT JOIN and we check that the second table hasn't matched:
SELECT table1.*
FROM table1
LEFT JOIN table2
ON table1.providerId = table2.providerId
WHERE table2.providerId IS NULL
Which of the three versions above performs better depends (mostly) on the cardinality of the two tables.
Sorry, I misunderstood the question. This should do the trick.
The first part of the query selects all the pairs userId - providerId. The second part removes all the ones present in table1.
SELECT U.userId, P.providerId
FROM (SELECT DISTINCT table1.userId FROM table1) U, table2 P
MINUS
SELECT table1.* FROM table1
EDIT
this is the table structure i have used to get the output
SQL> desc tab1
Name Null? Type
---------------------------- -------- ----------------
USERID NUMBER(38)
PROVIDERID NUMBER(38)
SQL> desc tab2
Name Null? Type
---------------------------- -------- ----------------
PROVIDERID NUMBER(38)
SQL> select distinct(a.userid),b.providerId from tab1 a, tab2 b
minus
select * from tab1 ;
USERID PROVIDERID
---------- ----------
1 102
1 103
1 105
1 108
1 109
1 110
2 101
2 105
2 106
2 107
2 108
2 109
2 110
13 rows selected.
SELECT a.userid, b.providerid FROM table1 a, table2 b
WHERE a.providerid IS NOT NULL
MINUS
SELECT userid, providerid FROM table1 a
WHERE a.providerid IS NOT NULL;
The query bring the desired output...
Thanks all for ur efforts.