Select distinct fields from multiple table - sql

Table 1 -
ID VehicleID
1 A
2 A
3 A
1 B
1 C
4 C
2 D
Table 2-
ID VehicleID VehicleNo
1 A AA
2 A AA
3 A
1 B BB
1 C CC
4 C CC
2 D DD
Output-
VehicleId VehicleNo
A AA
B BB
C CC
D DD

This is how I understood it; read comments within code.
SQL> with
2 -- calculate "RN" (so that you'd have something to match rows on)
3 a as
4 (select vehicleid,
5 row_number() over (order by vehicleid) rn
6 from (select distinct vehicleid from tab1)
7 ),
8 b as
9 (select vehicleno,
10 row_number() over (order by vehicleno) rn
11 from (select distinct vehicleno from tab2)
12 )
13 -- final query
14 select a.vehicleid, b.vehicleno
15 from a left join b on a.rn = b.rn;
VEHICLEID VEHICLENO
---------- ----------
A AA
B BB
C CC
D DD
SQL>

One simple method is aggregation:
select VehicleId, max(VehicleNo) as VehicleNo
from table2
group by VehicleId;

Related

SQL Take Max and Include Non-Group By COLS

TABLE1
ID STUDENT SCORE TIME
A 1 9 1
A 1 8 2
B 1 0 1
B 1 10 2
B 1 7 3
C 2 5 1
C 2 1 2
C 2 0 3
D 3 1 1
E 3 0 1
D 3 4 2
D 3 4 3
E 3 9 2
F 4 6 1
G 4 6 1
WANT
ID STUDENT MAXSCORE TIME
A 1 9 1
B 1 10 2
B 1 7 3
C 2 5 1
C 2 1 2
C 2 0 3
D 3 1 1
E 3 9 2
D 3 4 3
F 4 6 1
I have TABLE1 and wish for WANT which does this:
for every STUDENT/TIME, select the row with the MAX(SCORE)
I try this::
select ID, STUDENT, MAX(SCORE) AS MAXSCORE, TIME
from TABLE1
group by STUDENT, TIME
But amn't able to include ID
First get the max score by student/time, then join back to the original table.
WITH dat
AS
(
SELECT student, time, MAX(score) AS max_score
FROM TABLE1
GROUP BY student, time
)
SELECT DISTINCT t.id, t.student, d.max_score, t.time
FROM TABLE1 t
INNER JOIN dat d
ON t.student = d.student AND t.time = d.time AND t.score = d.max_score;
If the RDBMS supports window functions, then
with cte as (
select id,
student,
score,
time,
row_number() over (partition by student, time order by score desc) as rn
from table1)
select id, student, score, time
from cte
where rn = 1;

Select quantity on a 1st table based on a total quantity the 2nd table

Table 1
ID
Grp
Qty
1
A
5
2
A
4
3
B
5
4
B
3
5
B
2
6
C
14
7
D
1
8
D
1
9
E
2
10
E
2
11
E
1
12
E
1
Table 2
ID
Grp
Qty
1
A
7
2
B
9
3
C
13
4
D
1
5
E
4
Select/Output
ID
Grp
Qty
1
A
0
2
A
2
3
B
0
4
B
0
5
B
1
6
C
1
7
D
0
8
D
1
9
E
0
10
E
0
11
E
1
12
E
1
I want to select a row on a 1st table with a specific quantity based on the total quantity of the 2nd table. The result is on the 3rd table. Please see sample tables above, I really appreciate a help, thank you so much and sorry it was my first time asking a question here.
I have tried this code on both 2 tables
WITH tbl AS(
SELECT ID,
Qty,
Grp,
ROW_NUMBER() OVER (PARTITION BY Grp)AS Rown,
SUM(Qty) OVER (PARTITION BY Grp)AS Total
FROM Table1
)
SELECT * FROM tbl WHERE Rown = 1
But I am not able to select the specific rows on Table 1 because it only select the 1st row and total the quantity. Every row on table 1 has its own quantity.
You could use a cumulative windowed aggregates and then a CASE expression to achieve this:
--Saple Data
WITH Table1 AS(
SELECT *
FROM (VALUES(1,'A',5),
(2,'A',4),
(3,'B',5),
(4,'B',3),
(5,'B',2),
(6,'C',14))V(ID,Grp,Qty)),
Table2 AS(
SELECT *
FROM (VALUES(1,'A',7),
(2,'B',9),
(3,'C',13))V(ID,Grp,Qty)),
--Solution
CTE AS(
SELECT T1.ID,
T1.Grp,
T1.Qty,
SUM(T1.Qty) OVER (PARTITION BY T1.Grp ORDER BY T1.Id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS RunningQty,
T2.Qty AS T2Qty
FROM Table1 T1
JOIN Table2 T2 ON T1.Grp = T2.Grp)
SELECT C.ID,
C.Grp,
CASE WHEN C.RunningQty <= C.T2Qty THEN C.Qty
ELSE C.T2Qty - LAG(C.RunningQty,1,0) OVER (PARTITION BY C.Grp ORDER BY C.ID)
END AS Qty
FROM CTE C;

assign a new value based on combinations

I have these two tables
the first one has id's and a categorical variable 'code'
table1
id code
1 1 F
2 1 B
3 1 J
4 2 D
5 2 B
6 2 F
7 2 G
8 2 C
9 2 D
10 3 G
11 3 G
12 3 G
13 4 B
14 4 F
15 4 C
16 4 D
17 5 C
18 5 A
19 5 G
20 5 D
and table2
has some combinations of the categorical variable 'code' which are assigned a new category 'code3'
code1 code2 code_3
1 C B O
2 B A K
3 A C L
4 E B N
5 A D J
6 D B L
id's in table1 come with multiple codes, the combinations of those codes result in new codes found on table2.
how to I assign the id's in table1 the values in table2 code3 based on the combinations they have?
desired output
would be something like
id code
1 1 F
2 1 B
3 1 J
5 2 L -- added, while a B and D removed
6 2 F
7 2 G
8 2 C
...
You can get the list of new codes to add by doing a self-join and then joining to table2 to find matches:
select t1.id, t2.code3
from table1 t1 join
table1 tt1
on t1.id = tt1.id and
t1.code < t2.code join
table2 t2
on t2.code1 = t1.code and
t2.code2 = tt1.code;
SELECT id, code, NVL (code3, code)
FROM (SELECT id,
code,
hh,
rr,
gg,
code3
FROM ( SELECT id,
code,
hh,
code || hh rr
FROM --here rr is used as foreign key which refer gg ,which can used as primary key of table2
(SELECT id,
code,
LEAD (code, 1, code)
OVER (PARTITION BY id ORDER BY ROWNUM)
hh
FROM table1)
ORDER BY code, hh) e, --hh gives the code of next row of each code of table1
( SELECT code1 || code2 gg, code3
FROM table2
ORDER BY code1, code2) b
WHERE e.rr = b.gg(+))
ORDER BY id; --here left outer join is used to get desired output
-- ORDER BY code,hh and ORDER BY code1,code2 are used to make sure that SUM(D+B)=L AND SUM(B+D)=L

Smarter GROUP BY

Consider Table like this.
I will call it Test
Id A B C D
1 1 1 8 25
2 1 2 5 35
3 1 3 2 75
4 2 2 2 45
5 3 2 5 26
Now I want rows with max 'Id' Grouped by 'A'
Id A B C D
3 1 3 2 75
4 2 2 2 45
5 3 2 5 26
-
--Work, but I do not want
SELECT MAX(Id), A FROM Test GROUP BY A
--I want but do not work
SELECT MAX(Id), A, B, C, D FROM Test GROUP BY A
--Work but I do not want
SELECT MAX(Id), A, B, C, D FROM Test GROUP BY A, B, C, D
--Work and I want
SELECT old.Id, old.A, new.B, new.C, new.D
FROM(
SELECT
MAX(Id) AS Id, A
FROM
Test GROUP BY A
)old
JOIN Test new
ON old.Id = new.Id
Is there a better way to write last query without join
Most databases support window functions:
select *
from (
select *, row_number() over (partition by a order by id desc) rn
from test
) t
where rn = 1
Most DBMS now support Common Table Expressions (CTE). You can use one.
;with maxa as (
select row_number() over(partition by a order by id desc) rn,
id,a,b,c,d from test
)
select id,a,b,c,d
from maxa
where rn=1

How do I return the sum for this query?

I have the following tables I need to find out the sum.
Table A
ID Name
1 Jason
2 Peter
3 Ravi
Table B
ID ID_SEC
1 11
1 12
1 13
2 21
2 22
2 23
3 31
3 32
3 33
Table C
ID_SEC Value Include_Ind
11 100 Y
12 200 Y
13 300 N
21 10 Y
22 20 N
23 30 N
31 1000 N
32 2000 N
33 3000 N
Output
ID Name Total Include_Ind_count [only count when Y]
1 Jason 600 2
2 Peter 60 1
3 Ravi 6000 0
Use:
SELECT a.id,
a.name,
SUM(c.value) AS total
FROM TABLE_A a
JOIN TABLE_B b ON b.id = a.id
JOIN TABLE_C c ON c.id_sec = b.id_sec
GROUP BY a.id, a.name
The trick to counting INCLUDE_IND only when the flag is set to 'Y' is to use CASE() to test its value:
SQL> select a.id
2 , a.name
3 , sum ( c.val) as total
4 , count( case when c.include_ind = 'Y' then 1
5 else null end ) as inc_ind_cnt
6 from a
7 join b on ( b.id = a.id )
8 join c on ( c.id_sec = b.id_sec )
9 group by a.name, a.id
10 order by a.id
11 /
ID NAME TOTAL INC_IND_CNT
---------- ---------- ---------- -----------
1 Jason 600 2
2 Peter 60 1
3 Ravi 6000 0
SQL>
The ORDER BY is necessary to guarantee sort order since Oracle changed the algorithm it uses for GROUP BY operations in 10g.
You can use inner Joins and SUM for getting the result -
Assuming you tableC.Value is int field. Else you need to cast it.
SELECT tabA.id, tabA.name, SUM(tabC.value)
FROM TABLE_A tabA
INNER JOIN TABLE_B tabB ON tabB.id = tabA.id
INNER JOIN TABLE_C tabc ON tabC.id_sec = tabB.id_sec
GROUP BY tabA.id, tabA.name