Select from 5 Tables and show Results - sql

Table: Teacher
ID_Teacher Password Id_Users Name
--------------------------------------
1001 1234 1 A
1002 1234 2 B
Table: Student
Id_Student Password Id_Users Name
--------------------------------------
52001 1234 3 C
52002 1234 4 D
Table: Employee
Id_Employee Password Id_Users Name Country
--------------------------------------------------
60001 1234 5 E NewYork
60002 1234 6 F London
Table: Shop
Id_Shop Password Id_Users Name Country
--------------------------------------------------
70001 1234 7 G NewYork
70002 1234 8 H London
Table:Transaction
ID_Transaction Transaction_Of(Fk Id_Users) Method Recived_Transaction(Fk Id_Users) Money Status TimeStamp
----------------------------------------------------------------------------------------------------------------------
1 1 Tranfer 5 500 Sucess 2020-01-05 18:00:00
2 5 Tranfer 8 500 Sucess 2020-01-05 18:00:00
I need this
Result:
ID_Transaction Transaction_Of Method Recived_Transaction(Fk Id_Users) Money Status TimeStamp
----------------------------------------------------------------------------------------------------------------------
1 A Tranfer E 500 Sucess 2020-01-05 18:00:00
2 E Tranfer H 500 Sucess 2020-01-05 18:00:00
How I can write query?

This may work
$result = $this->db->select("t.ID_Transaction, c.Name, t.Method, e.Name, t.Money, t.Status, t.TimeStamp")
->join("Teacher as c" , "t.Transaction_Of = c.Id_Users")
->join("Employee as e" , "t.Recived_Transaction = e.Id_Users")
->get("Table_Transaction as t")->result_array();

Related

SQL - Period range in subgroups of a group by

I have the following dataset:
A
B
C
1
John
2018-08-14
1
John
2018-08-20
1
John
2018-09-03
2
John
2018-11-13
2
John
2018-12-11
2
John
2018-12-12
1
John
2020-01-20
1
John
2020-01-21
3
John
2021-03-02
3
John
2021-03-03
1
John
2020-05-10
1
John
2020-05-12
And I would like to have the following result:
A
B
C
1
John
2018-08-14
2
John
2018-11-13
1
John
2020-01-20
3
John
2021-03-02
1
John
2020-05-10
If I group by A, B the 1st row and the third just concatenate which is coherent. How could I create another columns to still use a group by and have the result I want.
If you have another ideas than mine, please explain it !
I tried to use some first, last, rank, dense_rank without success.
Use lag(). Looks like B is a function of A in your data. So checking lag(A) will suffice.
select A,B,C
from (
select *, case when lag(A) over(order by C) = A then 0 else 1 end startFlag
from mytable
) t
where startFlag = 1
order by C

BD2: SQL _CASE with group by

I have the following tables
---SALARY_ITEMS---
PERSONID | EMPLOYMENT _REF | GROUP1 | CODE | FROM | END | QUANTI
000101 XYX 400 11101 2020-02-12 2020-02-12 12
000101 XYX 300 1100 2020-01-29 2020-02-29 1
000102 XYY 450 11111 2020-02-01 2020-02-12 19
000102 XYY 400 11101 2020-02-02 2020-02-12 82
000103 XYA 500 1100 2020-02-10 2020-02-12 11
000104 XYB 700 1100 2020-01-12 2020-02-12 24
---PERSON ---
PERSONID NAME
000101 Carolina
000102 Helen
000103 Jack
000104 Anna
---EMPLOYMENT---
PERSONID EMPLOYMENT _REF POSITION
000101 XYX doctor
000102 XYY nurse
000103 XYA nurse
000104 XYB Proffesor
----absent---
PERSONID CODE2 FROM END
000101 123 2020-03-01 2020-06-30
000102 120 2020-02-05 2020-02-13
000102 123 2020-03-01 2020-03-28
000103 115 2020-05-05 2020-06-30
000104 123 2020-02-01 2020-05-30
What I tried to do: get all employee that they are doctor and nurse and have certain group with certain code and works over 100 hours in a 2020 -Feb.
The following SQL query give me what i want But i want to add something to my query that is :
create a new column to see if the employee was absent in the same period 2020-feb with absent code 120 or 119 or both.
If he was I will get the 'CODE2' ELSE 'NOTHING'.
How can I do this in DB2?
This is the result I need to get:
PERSONID | NAME | POSITION | QUANTITY |ABSENT (this what i want to have)
000102 Helen NURSE 101 120
Query:
SELECT
S.PERSONID, P.NAME,E.POSTION , sum(S.QUANTITY) as QUANTITY
FROM
SALARY_ITEMS S
LEFT JOIN
PERSON P ON S.PERSONID = P.PERSONID
LEFT JOIN
EMPLOYMENT E ON E.EMPLOYMENT_REF = S.EMPLOYMENT _REF
WHERE
S.group1 IN ('400', '440', '450', '470', '640')
AND S.code IN ('11101', '11111', '11121', '11131', '11141')
AND S.from >= '2020-02-01'
AND S.end <= '2020-02-29'
AND E.POSTION IN ('nurse', 'doctor')
AND (SELECT SUM(S2.QUANTITY) AS QUANTITY2
FROM SALARY_ITEMS S2
WHERE S2.group1 IN ('400', '440', '450', '470', '640')
AND S2.code IN ('11101', '11111', '11121', '11131', '11141')
AND S2.from >= '2020-02-01'
AND S2.end <= '2020-02-29'
AND S.PERSONID = S2.PERSONID) >= '100'
GROUP BY
S.PERSONID, P.NAME, E.POSTION

How to execute join between three slow change dimensions sort by all start date columns?

I'm trying to join data between three slow change dimension type 2. When I query the result, the sort by date between the dimensions are not as expected.
I have the slow change dimensions below:
Table Subsidiaries
id
name
subsidiary
department
start_date_dep
end_date_dep
last_record_flg
1
John Doe
AL
Engineering
2005-10-01
2013-01-01
0
1
John Doe
AL
Sales
2013-01-01
2014-05-01
0
1
John Doe
NY
Sales
2014-05-01
1
38
Ivy Johnson
NY
Sales
2020-06-01
1
Table Functions
id
function
start_date_fun
end_date_fun
last_record_flg
1
operator
2005-10-01
2009-08-01
0
1
leader
2009-08-01
2011-10-01
0
1
manager
2011-10-01
2017-07-01
0
1
director
2017-07-01
1
38
operator
2020-06-01
1
Table Graduations
id
university_graduation
conclusion_date
last_record_flg
1
bachelor
15/12/2005
0
1
master
15/12/2008
1
38
bachelor
15/12/2014
1
The desired result is:
id
name
subsidiary
department
start_date_dep
end_date_dep
last_record_flg
function
start_date_fun
end_date_fun
last_record_flg
university_graduation
conclusion_date
last_record_flg
max_date
seq
start
end
last_record_flg
1
John Doe
AL
Engineering
2005-10-01
2013-01-01
0
operator
2005-10-01
2009-08-01
0
bachelor
2005-12-15
0
2005-12-15
1
2005-10-01
2008-12-15
0
1
John Doe
AL
Engineering
2005-10-01
2013-01-01
0
operator
2005-10-01
2009-08-01
0
master
2008-12-15
1
2008-12-15
1
2008-12-15
2009-08-01
0
1
John Doe
AL
Engineering
2005-10-01
2013-01-01
0
leader
2009-08-01
2011-10-01
0
master
2008-12-15
1
2009-08-01
1
2009-08-01
2011-10-01
0
1
John Doe
AL
Engineering
2005-10-01
2013-01-01
0
manager
2011-10-01
2017-07-01
0
master
2008-12-15
1
2011-10-01
1
2011-10-01
2013-01-01
0
1
John Doe
AL
Sales
2013-01-01
2014-05-01
0
manager
2011-10-01
2017-07-01
0
master
2008-12-15
1
2013-01-01
1
2013-01-01
2014-05-01
0
1
John Doe
NY
Sales
2014-05-01
NULL
1
manager
2011-10-01
2017-07-01
0
master
2008-12-15
1
2014-05-01
1
2014-05-01
2017-07-01
0
1
John Doe
NY
Sales
2014-05-01
NULL
1
director
2017-07-01
NULL
1
master
2008-12-15
1
2017-07-01
1
2017-07-01
NULL
1
38
Ivy Johnson
NY
Sales
2020-06-01
NULL
1
operator
2020-06-01
NULL
1
bachelor
2014-12-15
1
2020-06-01
1
2020-06-01
NULL
1
I tried with CROSS APPLY, but is returning only one line for each id. I'm trying with CASE WHEN but the query output is not exactly equal the desired result. In my return the column 'FUNCTION' and 'START_DATE_FUN' not follow the sequence (sort) presented in the desired result, the same occur for columns 'UNIVERSITY_GRADUATION' and 'CONCLUSION_DATE'.
The query:
select
*
from(
select
tb.*
,row_number() over(partition by tb.id,tb.max_date order by tb.max_date) as seq
,tb.max_date as [start]
,lead( tb.max_date ) over( partition by tb.id order by tb.max_date ) as [end]
,case when lead( tb.max_date ) over( partition by tb.id order by tb.max_date ) is null then 1 else 0 end as last_record_flg
from(
select
sb.id
,sb.[name]
,sb.subsidiary
,sb.department
,sb.start_date_dep
,sb.end_date_dep
,sb.last_record_flg as lr_sb
,fc.[function]
,fc.start_date_fun
,fc.end_date_fun
,fc.last_record_flg as lr_fc
,gd.university_graduation
,gd.end_date_grad
,gd.last_record_flg as lr_gd
,case
when sb.start_date_dep >= fc.start_date_fun and sb.start_date_dep >= gd.end_date_grad then sb.start_date_dep
when fc.start_date_fun >= sb.start_date_dep and fc.start_date_fun >= gd.end_date_grad then fc.start_date_fun
else gd.end_date_grad
end as max_date
from
#Subsidiaries as sb
left outer join #Functions as fc
on sb.id = fc.id
left outer join #Graduations as gd
on sb.id = gd.id
) as tb
) as tb2
where
tb2.seq = 1
Below the DDL:
create table #Subsidiaries (
id int
,[name] varchar(15)
,subsidiary varchar(2)
,department varchar(15)
,start_date_dep date
,end_date_dep date
,last_record_flg bit
)
go
insert into #Subsidiaries values
(1,'John Doe','AL','Engineering','2005-10-01','2013-01-01',0),
(1,'John Doe','AL','Sales','2013-01-01','2014-05-01',0),
(1,'John Doe','NY','Sales','2014-05-01',null,1),
(38,'Ivy Johnson','NY','Sales','2020-06-01',null,1)
go
create table #Functions (
id int
,[function] varchar(15)
,start_date_fun date
,end_date_fun date
,last_record_flg bit
)
go
insert into #Functions values
(1,'operator','2005-10-01','2009-08-01',0),
(1,'leader','2009-08-01','2011-10-01',0),
(1,'manager','2011-10-01','2017-07-01',0),
(1,'director','2017-07-01',null,1),
(38,'operator','2020-06-01',null,1)
go
create table #Graduations (
id int
,university_graduation varchar(15)
,end_date_grad date
,last_record_flg bit
)
go
insert into #Graduations values
(1,'bachelor','2005-12-15',0),
(1,'master','2008-12-15',1),
(38,'bachelor','2014-12-15',1)
go
Case when someone find the same difficult to join two or more SCD type 2, I could find a reference in this link https://sqlsunday.com/2014/11/30/joining-two-scd2-tables/ (SQL Sunday) that help me to build the query and use the range intervals in the join condition to return result as desired.

JOIN on ID, IF ID doesn't match then match on other columns BigQuery

I have two tables that I am trying to join. The tables have a primary and foreign key but there are some instances where the keys don't match and I need to join on the next best match.
I tried to use a case statement and it works but because the join isn't perfect. It will either grab the incorrect value or duplicate the record.
The way the table works is if the Info_IDs don't match up we can use a combination of Lev1 and if the cust_start date is between Info_Start and Info_End
I need a way to match on the IDs and then the SQL stops matching on that row. But im not sure if that is something BigQuery can do.
Customer Table
Cust_ID Cust_InfoID Cust_name Cust_Start Cust_Lev1
1111 1 Amy 2021-01-01 A
1112 3 John 2020-01-01 D
1113 8 Bill 2020-01-01 D
Info Table
Info_ID Info_Lev1 Info_Start Info_End state
1 A 2021-01-15 2021-01-14 NJ
3 D 2020-01-01 2020-12-31 NY
5 A 2021-01-01 2022-01-31 CA
Expected Result
Cust_ID Cust_InfoID Info_ID Cust_Lev1 Cust_Start Info_Start Info_End state
1111 1 1 A 2021-01-01 2021-01-15 2021-01-14 NJ
1112 3 3 D 2020-01-01 2020-01-01 2020-12-31 NY
1112 8 3 D 2020-01-01 2020-01-01 2020-12-31 NY
Join Idea 1:
CASE
WHEN
(Cust_InfoID = Info_ID) = true
AND (Cust_Start BETWEEN Info_Start AND Info_End) = true
THEN
Cust_InfoID = Info_ID
ELSE
Cust_Start BETWEEN Info_Start AND Info_End
and Info_Lev1 = Cust_Lev1
END
Output:
Cust_ID Cust_InfoID Info_ID Cust_Lev1 Cust_Start Info_Start Info_End state
1111 1 5 A 2021-01-01 2021-01-01 2022-01-31 CA
1112 3 3 D 2020-01-01 2020-01-01 2020-12-31 NY
1113 8 3 D 2020-01-01 2020-01-01 2020-12-31 NY
The problem here is that IDs match but the dates don't so it uses the ELSE statement to join. This is incorrect
Join Idea 2:
CASE
WHEN
Cust_InfoID = Info_ID
THEN
Cust_InfoID = Info_ID
ELSE
Cust_Start BETWEEN Info_Start AND Info_End
and Info_Lev1 = Cust_Lev1
END
Output:
Cust_ID Cust_InfoID Info_ID Cust_Lev1 Cust_Start Info_Start Info_End state
1111 1 1 A 2021-01-01 2021-01-15 2021-01-14 NJ
1111 1 5 A 2021-01-01 2021-01-01 2022-01-31 CA
1112 3 3 D 2020-01-01 2020-01-01 2020-12-31 NY
1113 8 3 D 2020-01-01 2020-01-01 2020-12-31 NY
The problem here is that IDs match but the ELSE statement also matches up the wrong duplicate row. This is also incorrect
Example tables here:
with customer as (
SELECT 1111 Cust_ID,1 Cust_InfoID,'Amy' Cust_name,'2021-01-01' Cust_Start,'A' Cust_Lev1
UNION ALL
SELECT 1112,3,'John','2020-01-01','D'
union all
SELECT 1113,8,'Bill','2020-01-01','D'
),
info as (
select 1 Info_ID,'A' Info_Lev1,'2021-01-15' Info_Start,'2021-01-14' Info_End,'NJ' state
union all
select 3,'D','2020-01-01','2020-12-31','NY'
union all
select 5,'A','2021-01-01','2022-01-31','CA'
)
select Cust_ID,Cust_InfoID,Info_ID,Cust_Lev1,Cust_Start,Info_Start,Info_End,state
from customer
join info on
[case statement here]
The way the table works is if the Info_IDs don't match up we can use a combination of Lev1 and if the cust_start date is between Info_Start and Info_End
Use two left joins, one for each of the conditions:
select c.*,
coalesce(ii.info_start, il.info_start),
coalesce(ii.info_end, il.info_end),
coalesce(ii.state, il.state)
from customer c left join
info ii
on c.cust_infoid = ii.info_id left join
info il
on ii.info_id is null and
c.cust_lev1 = il.info_lev1 and
c.cust_start between il.info_start and il.info_end
Consider below ("with one JOIN and a CASE statement" as asked)
select any_value(c).*,
array_agg(i order by
case when c.cust_infoid = i.info_id then 1 else 2 end
limit 1
)[offset(0)].*
from `project.dataset.customer` c
join `project.dataset.info` i
on c.cust_infoid = i.info_id
or(
c.cust_lev1 = i.info_lev1 and
c.cust_start between i.info_start and i.info_end
)
group by format('%t', c)
when applied to sample data in your question - output is

SQL get latest record for each ID

I have three tables that contains data as below:
Users
Id Name Other_Columns
---------------------------
1 John Blah
2 Ricky Blah
3 Stella Blah
4 Bob Blah
Saldo
Id User_id Saldo
--------------------
1 3 0.00
2 1 9.00
3 2 0.15
4 4 3.50
Payments
Id User_id Amount Paid_date
------------------------------------------
1 2 10.00 2014-09-01 08:10
2 2 25.00 2014-09-01 09:00
3 3 100.00 2014-05-10 12:47
4 1 20.50 2014-02-23 15:30
How to get result like this:
Id Name Saldo Last Payment
------------------------------------------
1 John 9.00 23.02.2014 20.50
2 Ricky 0.15 01.09.2014 25.00
3 Stella 0.00 0000-00-00 0.00
4 Bob 3.50 10.05.2014 100.00
Thank you.
select u.id, u.name, s.saldo, p.last_paid_date, p2.amount
from users u
join saldo s
on u.id = s.user_id
join (select user_id, max(paid_date) as last_paid_date
from payments
group by user_id) p
on u.id = p.user_id
join payments p2
on p.last_paid_date = p2.paid_date
and p.user_id = p2.user_id
This answer assumes:
(1) On table SALDO, there is one row per USER_ID
(2) On table PAYMENTS, there can be multiple rows per USER_ID
(I'm pretty confident about #2 being true, I don't know about #1, as you didn't say and your sample data doesn't indicate one way or the other)