Select unique subsets - sql

I have a table like in example below.
SQL> select * from test;
ID PARENT_ID NAME
1 1 A
2 1 B
3 2 A
4 2 B
5 3 A
6 3 B
7 3 C
8 4 A
What I need is to get all unique subsets of names ((A,B), (A,B,C), (A)) or exclude duplicate subsets. You can see that (A,B) is twice there, one for PARENT_ID=1 and one for 2.
I want to exclude such duplicates:
ID PARENT_ID NAME
1 1 A
2 1 B
5 3 A
6 3 B
7 3 C
8 4 A

You can use DISTINCT to only return different values.
e.g.
SELECT DISTINCT GROUP_CONCAT(NAME SEPARATOR ',') as subsets
FROM TABLE_1
GROUP BY PARENT_ID;
SQL Fiddle

I have used 'group_concat' assuming you are using 'Mysql'. The equivalent function in Oracle is 'listagg()'. you can see it in action here in SQL fiddle
Here is the solution:-
Select a.* from
test a
inner join
(
Select nm, min(parent_id) as p_id
from
(
Select Parent_id, group_concat(NAME) as nm
from test
group by Parent_ID
) a
group by nm
)b
on a.Parent_id=b.p_id
order by parent_id, name

Related

Find rows that contains same value on different columns

The table to find which rows contains same value on two different columns for 2 rows. Here is a small sample rows among 2k+ rows.
id left right
1 3 4
2 4 1
3 1 9
4 2 6
5 2 5
6 9 8
7 0 7
In the above case, I need to get row 1,2,3,6 as it contains 4 on two rows of two different columns i.e (id=1&2),1 on two rows of two different columns(id=1&3) and 9 on two rows of two different columns(id=3&6)
My thoughts:
I did thought many things for example cross join on left and right column, group by and count etc.
with Final as (With OuterTable as (WITH Alias AS (SELECT id as left_id , left FROM Test)
SELECT DISTINCT id, left_id FROM Alias
INNER JOIN Test ON Alias.left = Test.right)
SELECT id from OuterTable
UNION ALL
SELECT left_id from OuterTable)
SELECT DISTINCT * from Final;
It's messy, but it works.
You can do it with EXISTS:
SELECT t1.*
FROM tablename t1
WHERE EXISTS (
SELECT 1 FROM tablename t2
WHERE t1.id <> t2.id AND (t2.left = t1.right OR t1.left = t2.right)
)
See the demo.
Results:
id
left
right
1
3
4
2
4
1
3
1
9
6
9
8

Create multiple rows based on 1 column

I currently have a table with a quantity in it.
ID Code Quantity
1 A 1
2 B 3
3 C 2
4 D 1
Is there anyway to write a sql statement that would get me
ID Code Quantity
1 A 1
2 B 1
2 B 1
2 B 1
3 C 1
3 C 1
4 D 1
I need to break out the quantity and have that many number of rows
Thanks
Here's one option using a numbers table to join to:
with numberstable as (
select 1 AS Number
union all
select Number + 1 from numberstable where Number<100
)
select t.id, t.code, 1
from yourtable t
join numberstable n on t.quantity >= n.number
order by t.id
Online Demo
Please note, depending on which database you are using, this may not be the correct approach to creating the numbers table. This works in most databases supporting common table expressions. But the key to the answer is the join and the on criteria.
One way would be to generate an array with X elements (where X is the quantity). So for rows
ID Code Quantity
1 A 1
2 B 3
3 C 2
you would get
ID Code Quantity ArrayVar
1 A 1 [1]
2 B 3 [1,2,3]
3 C 2 [2]
using a sequence function (e.g, in PrestoDB, sequence(start, stop) -> array(bigint))
Then, unnest the array, so for each ID, you get a X rows, and set the quantity to 1. Not sure what SQL distribution you're using, but this should work!
You can use connect by statement to cross join tables in order to get your desired output.
check my solution it works pretty robust.
select
"ID",
"Code",
1 QUANTITY
from Table1, table(cast(multiset
(select level from dual
connect by level <= Table1."Quantity") as sys.OdciNumberList));

Formulating Query

I have a table 'TempC3'
Itemset itemset2
1 3
2 3
2 5
3 5
I want combination of elements in these columns without repetition. So the output table shall be
Itemset itemset2 Itemset3
1 3 5
2 3 5
1 2 3
I designed a query but it wont return the last row of the desired output table -
Select distinct a.Itemset,
a. Itemset2,
c.itemset2
from TempC3 a
Join TempC3 c
ON c.Itemset2 > a.Itemset2
This query only results this:
Itemset itemset2 Itemset3
1 3 5
2 3 5
Since you want all combinations of itemsets, you have to concatenate the two columns in your input table into a single column first. You could do this, for example, using a CTE:
Fiddle Here
WITH CTE AS (
SELECT Itemset FROM TempC3
UNION
SELECT Itemset2 FROM TempC3
)
SELECT I1.Itemset, I2.Itemset, I3.Itemset FROM CTE AS I1
INNER JOIN CTE AS I2 ON I2.Itemset > I1.Itemset
INNER JOIN CTE AS I3 ON I3.Itemset > I2.Itemset

SQL select Name entries for which a certain requirement is NEVER fulfilled

I need to select Name entries for which none of the rows fulfills a certain requirement. This is best described as an example- lets consider the following table:
Name Number ID
A 1 2
A 2 2
B 1 2
B 2 3
C 3 3
The requirement would be that Number=ID. For the name B this is never the case, so I would like to return the Name B.
Name Number ID
A 1 2
A 2 2 <---- fulfills requirement for A
B 1 2
B 2 3
C 3 3 <---- fulfills requirement for C
Is this possible in SQL?
You can use a NOT EXISTS clause
select * from Table1 t1
where not exists (select null
from Table1
where t1.Name = Name
and Number = Id)
If you just want the names which don't fulfill the requirement, just change the select to
select distinct t1.Name
see SqlFiddle with both versions.
Try this
Select Name
from table
where name not in (Select distinct name from table where number = id )

Most efficient way to get lists?

What's the best way to get a sublist of things?
I have two tables:
create table A (
id int primary key
)
create table B (
id int primary key,
aid int foreign key references A( id ),
sort_key int
)
I want to get a list of objects A, with subobjects B, but only the top five of B.
Let's say A is people, and B is type of food, with sort_key being how much a person likes that food. How do I get everybody (or some people) and their top 5 food?
On the previous comment if it's an INT you can't put non numerics in there.
Assuming the following data:
a
--
id
1
2
3
b
------------------------
id aid sort_key
1 1 1
2 1 2
3 2 1
4 3 1
5 1 3
6 1 4
7 1 5
8 1 6
9 2 2
10 2 3
The following query in MySQL would give you this:
SELECT a.*,
(SELECT GROUP_CONCAT(id) AS ids FROM b AS bi WHERE bi.aid = a.id ORDER BY sort_key LIMIT 5) AS ids
FROM a
Result:
id ids
1 1,2,5,6,7,8
2 3,9,10
3 4
This query assumes the sort key is one based, rather than zero:
SELECT a.name
b.food
FROM A a
JOIN B b ON b.aid = a.id
WHERE b.sortkey <= 5
ORDER BY a.name, b.sortkey