Group by and select columns not included in the aggregate - sql

Given I have columns A B C D ….. Z
I want to Group-By on A, B , C Having Count(*) > 1 and then for each of those rows, I want to SELECT the rest of the Columns as well that were not included in the aggregate.
The result would be like
Occurrences A B C D E F G ------- Z
3 e e k q r y e ------- j
3 e e k f t d t ------- y
3 e e k w e q c ------- d
2 f r s w e q c ------- d
2 f r s w e q c ------- d
How can I do that?

You don't want GROUP BY, you want ORDER BY. To get the first column, you can use window functions, which are ANSI standard and supported by most databases:
select t.*
from (select count(*) over (partition by a, b, c) as occurrences,
t.*
from t
order by a, b, c
) t
where occurrences > 1;

Related

SQL parent child hierarchy level columns

I need to transform this:
PositionID
ReportsToID
A
B
A
C
B
D
C
E
D
Into this:
PositionID
ReportsToID
Level 1 ID
Level 2 ID
Level 3 ID
Level 4 ID
Level 5 ID
A
A
B
A
A
B
C
B
A
B
C
D
C
A
B
C
D
E
D
A
B
C
D
E
I am a complete SQL novice and no idea how to tackle this... Any help would be greatly appreciated!
Googling for code that has done this already - have not found any
I decided to write a generic solution for unlimited levels. It's possible to walk all the levels using a recursive CTE.
For example:
with recursive
n as (
select position_id, reports_to_id, reports_to_id as rti,
cast(position_id as varchar) as pt
from t
union all
select n.position_id, n.reports_to_id, t.reports_to_id,
t.position_id || ' < ' || n.pt
from n
join t on n.rti = t.position_id
)
select position_id, reports_to_id, pt from n where rti is null
Result:
position_id reports_to_id pt
------------ -------------- -----------------
A null A
B A A < B
C B A < B < C
D C A < B < C < D
E D A < B < C < D < E
See running example at db<>fiddle.
If you need a static solution with a specific number of columns, it can be done with multiple unioned-queries, each one with an increasing number of joins.

HOW TO PRINT A TO Z ALPHABETS IN QUERY WITHOUT USING TABLE

HOW TO PRINT A TO Z ALPHABETS IN QUERY WITHOUT USING TABLE
For Oracle, here's one option:
SQL> select chr(level + 64) letter
2 from dual
3 connect by level <= ascii('Z') - ascii('A') + 1;
LETTER
----------
A
B
C
D
E
F
<snip>
X
Y
Z
26 rows selected.
SQL>
For Postgres:
select chr(code)
from generate_series(ascii('A'), ascii('Z')) as t(code)
order by code
select chr(generate_series(65,97));
output
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z

How to extract non grouped column data?

I have a table A with following data:
A:
colA colB
a x
b x
c y
d y
e z
f z
I want the output as:
colA colA_1
a b
c d
e f
I.e. I want to group the data based on colB and fetch the values from colA. I know that the same value will appear exactly twice in colB.
What I am trying to do is:
SELECT a1.colA, a2.colA
FROM A a1
JOIN A a2
ON a1.colA != a2.colA and a1.colB=a2.colB;
But this gives the output as:
colA colA_1
a b
b a
c d
d c
e f
f e
How can I fix this to get the desired output?
No need to join, simply do a GROUP BY:
SELECT min(colA), max(colA)
FROM A
group by colB

Join only the partitions of two tables

SQL Server 2008
Table A looks like:
A_ID v1 v2 v3
---------------------------
1 d e f
1 a b c
1 a b d
2 d a b
2 e f g
3 d e f
3 e f g
3 d a b
and Table B is similar:
B_ID v1 v2 v3
---------------------------
Q a b c
Q b a c
Q a b d
R d e f
R a b c
R d e f
P e f g
P d a b
What I need back from these two tables are the (A_ID, B_ID) pairs, if any, where each row of Table B where B_ID = any one value has one matching row in Table A where A_ID = any one value. In other words, I need to the complete matching set in A for each full set of triples in B--no super sets or subsets. The value of B_ID and A_ID is immaterial.
I thought partitioning would be the way to go, since I already have the column that naturally partitions A and B, and I also thought I could pre-select which paritions where JOINed by ensuring only partitions with matching numbers of rows would be attempting. I haven't been able to do either--partitioning both tables was easy, but I see no way to tell the join to only act on the partitions.
In this example, (2,P) would be returned because all rows in Set P match all rows in Set 2. Result (1, R) would NOT be returned because all rows of Set R are not matched by all rows of Set 1, etc.
Using symetric difference:
SELECT DISTINCT a1.A_ID, b1.B_ID
FROM A a1,B b1
WHERE NOT EXISTS (
(SELECT v1,v2,v3
FROM A WHERE A.A_ID = a1.A_ID
EXCEPT
SELECT v1,v2,v3
FROM B WHERE B.B_ID = b1.B_ID
)
UNION ALL
(
SELECT v1,v2,v3
FROM B WHERE B.B_ID = b1.B_ID
EXCEPT
SELECT v1,v2,v3
FROM A WHERE A.A_ID = a1.A_ID)
);
LiveDemo

What is the difference between WITH Query and SELECT Query?

Data : I have written two queries one is WITH and Other is SELECT and then self joining the table below, but both queries return different results, why it happens ?
table name is test_cur
ID_SOURCE_CUR ID_TARGET_CUR
------------- --------------
A B
B C
C D
D E
A Z
G A
K A
Q A
J J
K K
K L
L K
B A
Z A
So why the two queries below return different results ?
SELECT *
FROM test_cur tu, test_cur fu
WHERE tu.id_target_cur = 'A'
AND fu.id_source_cur = 'A'
AND tu.id_source_cur <> fu.id_target_cur;
returns 8 rows.
ID_SOURCE_CUR ID_TARGET_CUR ID_SOURCE_CUR_1 ID_TARGET_CUR_1
-------------- -------------- -------------- --------------
G A A B
K A A B
Q A A B
Z A A B
G A A Z
K A A Z
Q A A Z
B A A Z
And -
WITH qry1 AS
(SELECT *
FROM test_cur)
SELECT *
FROM qry1 tu, qry1 fu
WHERE tu.id_target_cur = 'A'
AND fu.id_target_cur = 'A'
AND tu.id_source_cur <> fu.id_target_cur;
returns 25 rows.
ID_SOURCE_CUR ID_TARGET_CUR ID_SOURCE_CUR_1 ID_TARGET_CUR_1
-------------- -------------- -------------- --------------
G A G A
G A K A
G A Q A
G A B A
G A Z A
K A G A
K A K A
K A Q A
K A B A
K A Z A
Q A G A
Q A K A
Q A Q A
Q A B A
Q A Z A
B A G A
B A K A
B A Q A
B A B A
B A Z A
Z A G A
Z A K A
Z A Q A
Z A B A
Z A Z A
Why ?
Your second query is different, you have a different WHERE clause. The first WHERE is :
WHERE tu.id_target_cur = 'A'
AND fu.id_source_cur = 'A'
AND tu.id_source_cur <> fu.id_target_cur;
The second is:
WHERE tu.id_target_cur = 'A'
AND fu.id_target_cur = 'A' -- this line is different, it should be fu.id_source_cur = 'A'
AND tu.id_source_cur <> fu.id_target_cur;
Change those and the results are the exact same on both queries.
The where clauses are different fu.id_source_cur = 'A' vs. fu.id_target_cur = 'A'