How can I get that MAX 3 months with not NULL?
As result I need UserId, UserAgreementId and MAX Not NULL And Group BY UserId
month
Id
UserId
UserAgreementId
SubsriptionDate
Amount
1
NULL
NULL
NULL
NULL
NULL
2
12
222
33333
2020-02-02 00:00:00.000
40000
3
NULL
NULL
NULL
NULL
NULL
4
13
222
33333
2020-04-03 00:00:00.000
5000
5
NULL
NULL
NULL
NULL
NULL
6
15
222
33333
2020-06-04 00:00:00.000
7000
7
16
222
33333
2020-07-02 00:00:00.000
8000
8
17
222
33333
2020-08-09 00:00:00.000
4000
9
NULL
NULL
NULL
NULL
NULL
10
NULL
NULL
NULL
NULL
NULL
11
NULL
NULL
NULL
NULL
NULL
12
NULL
NULL
NULL
NULL
NULL
As Result must be smth like this
UserId
UserAgreementId
MAX
222
33333
3
Table AgreementId have SubsriptionDate in rows and I need to calculate period with max not empty Amount
UserAgreementId
SubsriptionDate
Amount
33333
2020-02-02 00:00:00.000
40000
33333
2020-04-03 00:00:00.000
5000
33333
2020-06-04 00:00:00.000
7000
33333
2020-07-02 00:00:00.000
8000
33333
2020-08-09 00:00:00.000
4000
What you're asking for is too complex for a query - it will take a long time to run.
For example, I've put together a draft below that just about gets the longest duration for each user, yet it references the same table 5 times.
This is barely readible, convuluted, and will tax the server more than you want.
Instead, fetch the records and process them in a more suitable programming language.
SELECT t.user_id, MAX(t.monthsTotal - s.monthsTotal + 1) AS longestDuration
FROM (SELECT a.*, YEAR(a.subscriptionDate) * 12 + a.month AS monthsTotal
FROM table_name) as t
INNER JOIN (SELECT a.*, YEAR(a.subscriptionDate) * 12 + a.month AS monthsTotal
FROM table_name AS a
LEFT OUTER JOIN table_name AS preceeding
ON a.user_id = preceeding.user_id
AND YEAR(a.subscriptionDate) * 12 + a.month = YEAR(preceeding.subscriptionDate) * 12 + preceeding.month + 1
WHERE preceedingMonth.id IS NULL) AS s
ON t.user_id = s.user_id
AND t.monthsTotal >= s.monthsTotal
LEFT OUTER JOIN (SELECT a.*, YEAR(a.subscriptionDate) * 12 + a.month AS monthsTotal
FROM table_name AS a
LEFT OUTER JOIN table_name AS preceeding
ON a.user_id = preceeding.user_id
AND YEAR(a.subscriptionDate) * 12 + a.month = YEAR(preceeding.subscriptionDate) * 12 + preceeding.month + 1
WHERE preceedingMonth.id IS NULL) AS dummy
ON t.user_id = dummy.user_id
AND dummy.monthsTotal > s.monthsTotal
AND t.monthsTotal > dummy.monthsTotal
WHERE dummy.id IS NULL
GROUP BY t.user_id
Related
I am using SAS Enterprise Guide 8.3 to connect IBM DB2.
I want to join and fill missing date and values.
I have a full calendar date table from 1/1/2021 up to yesterday.
Each ID can work 5 days to 7 days a week.
There is no target for Sunday.
4/3/2022 is Sunday.
Code is
SELECT t2.ID,
t1.CAL_DT, COALESCE(t2.EXPRESS,0) AS EXPRESS, COALESCE(t2.OTHRES,0) AS OTHRES , COALESCE(t2.CPRO_RPT,0) AS Total
FROM WORK.QUERY_FOR_DATE t1
left outer JOIN WORK.QUERY_FOR_CPRO_0000 t2 on t1.cal_dt = t2.cal_dt
ORDER BY t2.ID asc ,t1.CAL_DT asc;
Sample tables are below.
Table 1.
ID
Date
Express
Others
Total
001
4/1/2022
0
2
2
001
4/2/2022
2
3
5
001
4/4/2022
1
2
3
001
4/5/2022
2
2
4
002
4/1/2022
0
3
3
002
4/4/2022
3
3
6
002
4/5/2022
1
2
3
003
4/1/2022
3
3
6
003
4/2/2022
4
4
8
003
4/3/2022
1
1
2
003
4/4/2022
3
4
7
003
4/6/2022
2
4
6
Table 2.
ID
Date
Target
001
4/1/2022
4
001
4/2/2022
4
001
4/4/2022
4
001
4/5/2022
4
002
4/1/2022
6
002
4/2/2022
6
002
4/4/2022
6
002
4/5/2022
6
003
4/1/2022
8
003
4/2/2022
8
003
4/4/2022
8
003
4/5/2022
8
I want the result in Table 3.
ID
Date
Express
Others
Total
Target
001
4/1/2022
0
2
2
4
001
4/2/2022
2
3
5
4
001
4/3/2022
0
0
0
0
001
4/4/2022
1
2
3
4
001
4/5/2022
2
2
4
4
002
4/1/2022
0
3
3
6
002
4/2/2022
0
0
0
6
002
4/3/2022
0
0
0
0
002
4/4/2022
3
3
6
6
002
4/5/2022
1
2
3
6
003
4/1/2022
3
3
6
8
003
4/2/2022
4
4
8
8
003
4/3/2022
1
1
2
0
003
4/4/2022
3
4
7
8
003
4/5/2022
2
4
6
8
I would use your date table to cross join with your ID to build a permutation of those two, then you can join ID back into the set and get a full set of ID and Dates along with your real data from your CPRO table. You could join back in again between MIN and MAX date to remove all the dates in your date table.
SELECT X.ID, X.CAL_DT
, COALESCE(T3.EXPRESS,0) EXPRESS
, COALESCE(T3.OTHRES,0) OTHRES
, COALESCE(T3.CPRO_RPT,0) CPRO_RPT
FROM ( SELECT DISTINCT T2.ID, T1.CAL_DT FROM (WORK.QUERY_FOR_DATE t1 CROSS JOIN WORK.QUERY_FOR_CPRO_0000 t2)) X
LEFT OUTER JOIN WORK.QUERY_FOR_CPRO_0000 T3
ON X.ID = T3.ID
AND X.CAL_DT = T3.CAL_DT
You could also add another join to keep you date range correct if you didn't want to hard code it in the where clause.
SELECT
X.ID
, X.CAL_DT
, COALESCE(T3.EXPRESS,0) EXPRESS
, COALESCE(T3.OTHRES,0) OTHRES
, COALESCE(T3.CPRO_RPT,0) CPRO_RPT
FROM
(
SELECT DISTINCT T2.ID, T1.CAL_DT
FROM (WORK.QUERY_FOR_DATE t1
CROSS JOIN WORK.QUERY_FOR_CPRO_0000 t2)) X
LEFT OUTER JOIN WORK.QUERY_FOR_CPRO_0000 T3
ON X.ID = T3.ID
AND X.CAL_DT = T3.CAL_DT
INNER JOIN
(SELECT MIN(DT) AS MINDATE, MAX(DT) AS MAXDATE
FROM WORK.QUERY_FOR_CPRO_000) AS DATEPARAM
ON X.CAL_DT BETWEEN MINDATE AND MAXDATE
Since you have a Calendar table, you may try the following:
Select B.id, C.CAL_DT, COALESCE(D.express, 0) express, COALESCE(D.others, 0) others,
COALESCE(D.total, 0) total, COALESCE(E.target, 0) target
From Calendar C
Cross Join (Select Distinct id From Table1) B
Left Join table1 D
On D.id = B.id And D.date_ = C.CAL_DT
Left Join table2 E
On E.id = B.id And E.date_ = C.CAL_DT
Order By B.id, C.CAL_DT
First, you have to join each id from table1 to every day in your calendar table, and that done by cross join the calendar with the distinct ids from table1.
Now, left join that result to table1, table2 to get which ids not having entries for a specific date (null values).
The COALESCE function is used to replace null values with 0.
See a demo using DB2 from db<>fiddle.
I have multiple tables having date_modified column, and I need to create a view using all these tables but date_modified should be max of date_modified of these tables.
table1
id vendor_number fiscal_year date_created date_modified
1 124 2021 2021/11/01 2021/11/02
2 231 2021 2021/11/01 2021/11/03
3 232 2021 2021/11/02 NULL
4 234 2021 2021/11/02 NULL
table2
id fiscal_year discount_amt date_created date_modified
1 2021 10.30 2021/11/01 2021/11/03
2 2021 15.23 2021/11/01 2021/11/02
3 2021 17.45 2021/11/02 2021/11/02
4 2021 18.49 2021/11/02 NULL
table3
id vendor_number date_created date_modified
1 124 2021/11/01 2021/11/04
2 231 2021/11/01 2021/11/01
3 232 2021/11/01 2021/11/03
4 234 2021/11/02 2021/11/03
Required Output :
id|fiscal_year|discount_amt|vendor_number|date_created|date_modified
1 | 2021 | 10.30 | 124 | 2021/11/01 | 2021/11/04
2 | 2021 | 15.23 | 231 | 2021/11/01 | 2021/11/03
3 | 2021 | 17.45 | 232 | 2021/11/02 | 2021/11/03
4 | 2021 | 18.49 | 234 | 2021/11/02 | 2021/11/03
VIEW SQL:
CREATE VIEW view_data
AS
SELECT T1.id, T1.fiscal_year, T2.discount_amt, T3.vendor_number, T1.date_created, max(multiple date_modified columns..from multiple tables..)
FROM table1 AS T1
LEFT JOIN table2 AS T2
ON T1.id = T2.id
LEFT JOIN T3 v
ON T1.vendor_number = T3.vendor_number;
Assuming the id columns are keys of each table you can join them (using full outer join maybe) and then use GREATEST() to get the latest date.
For example:
create view v as
select
coalesce(a.id, b.id, c.id) as id,
b.fiscal_year,
b.discount_amt,
a.date_created,
greatest(a.date_modified, b.date_modified, c.date_modified) as date_modified
from table1 a
full join table2 b on b.id = a.id
full join table3 c on c.id = b.id or c.id = a.id
EDIT: If your version of DB2 doesn't implement GREATEST() you can replace it with the [rather long] CASE clause:
case when a.date_modified > b.date_modified then
case when a.date_modified > c.date_modified
then a.date_modified else c.date_modified end
else
case when b.date_modified > c.date_modified
then b.date_modified else c.date_modified end
end
Alternatively, you can implement the function yourself. It's pretty straightforward. For example:
create function greatest(in a date, in b date) returns date
language sql
begin
if a > b then return a; end if;
return b;
end
//
See running example of this custom function at db<>fiddle 1.
EDIT #2: Dealing with nulls
Nulls are not values, and the behavior of the database is correct. In the presence of an unknown date the engine cannot determine which date is greater and returns UNKNOWN -- in the form of a null.
Now, if you want nulls to behave as in programming languages like C, Java, PHP, then you can either 1) Use a lot of CASE/COALESCE clauses or you can simply modify your custom function to wotk as you please. Below is an example of the modified custom function:
create function mygreatest(in a date, in b date) returns date
language sql
begin
if a is null then return b; end if;
if b is null then return a; end if;
if a > b then return a; end if;
return b;
end
Then, you can see it in action:
with data (x, y) as (
select date '2021-07-01', date '2021-12-01' from sysibm.sysdummy1
union all select date '2021-07-01', null from sysibm.sysdummy1
union all select null, date '2021-12-01' from sysibm.sysdummy1
union all select null, null from sysibm.sysdummy1
)
select mygreatest(x, y) as g from data;
Result:
G
----------
2021-12-01
2021-07-01
2021-12-01
null
See running example at db<>fiddle 2.
I am looking for a SQL query to update all the columns in table A which has a NULL value to NOT NULL values from table C using reference as table B. All the columns in table A should be updated using a single query or dynamic query. Values should be updated based on column name and values should not be hard coded.
Table A
ID Name zip city Mdate
10001 Sarah NULL NULL 02-20-2018
98765 AJ NULL Ohio 01-15-2018
12345 NULL 7511 Texas 03-08-2018
Table B
ID RollNo Cdate
12345 1 01-18-2018
12345 2 01-22-2018
12345 3 03-20-2018
98765 9 01-18-2018
98765 8 01-22-2018
98765 7 03-20-2018
10001 10 03-08-2018
10001 11 01-15-2018
10001 12 02-20-2018
TABLE C
Rollno Name Zip City Mdate Cdate Modifyby
1 NULL 7511 Texas 01-18-2018 02-02-2017 #John
2 John 5001 NULL 01-22-2018 11-01-2017 #Krish
3 NULL 7000 Ohio 03-20-2018 11-15-2017 #Maria
10 Sarah NULL NULL 03-08-2018 10-05-2017 #tom
11 Tom NULL NULL 01-15-2018 04-05-2017 #Sony
12 NULL 5500 Pune 02-20-2018 03-25-2017 #Sandy
9 AJ NULL Ohio 01-18-2018 10-07-2017 #Mandy
8 NULL NULL NULL 01-12-2018 11-02-2017 #Deck
7 NUll 8000 NULL 01-12-2018 12-05-2017 #Ant
Output:
ID Name zip city Mdate Cdate Modifyby
10001 Sarah 5500 Pune 02-20-2018 03-25-2017 #Sandy
98765 AJ 8000 Ohio 01-18-2018 10-07-2017 #Mandy
12345 John 7511 Texas 03-08-2018 10-05-2017 #tom
In the output, all the NULL column values in table A are updated with NOT NULL values from table C. Please provide a single query to update all the NULL columns in a single query itself.
I am trying below query but unable to update the table with max Function. Is there any alternative for it.
Select * into #temp FROM
(
SELECT A.ID,
Row_number() over(partition by A.ID order by A.mdate desc) as
RNK,C.NAME,C.ZIP,C.CITY,C.MDate,C.Cdate,C.Modifyby
FROM tableA A
INNER JOIN tableB B ON A.ID = B.ID
INNER JOIN tableC C ON B.RollNo = C.RollNo
)X where RNK = 1
UPDATE A SET Name =
CASE
WHEN MAX(A.Name) IS NULL THEN MAX(C.Name)
ELSE Max(A.Name) END
, Zip =
CASE
WHEN MAX(A.Zip) IS NULL THEN Max(C.Zip)
ELSE MAX(A.Zip)
END ,
City =CASE
WHEN MAX(A.City) IS NULL THEN Max(C.City)
ELSE MAX(A.City)
END
FROM #temp A
INNER JOIN TableB B ON A.ID = B.ID
INNER JOIN tablec C ON B.RollNo = C.RollNo
Getting an error:
An aggregate may not appear in the set list of an UPDATE statement.
I need all the values in output table along with null values updated with not null values.
Try this below script-
DEMO HERE
SELECT A.ID,
CASE
WHEN MAX(A.Name) IS NULL THEN MAX(C.Name)
ELSE Max(A.Name)
END Name,
CASE
WHEN MAX(A.Zip) IS NULL THEN Max(C.Zip)
ELSE MAX(A.Zip)
END Zip,
CASE
WHEN MAX(A.City) IS NULL THEN Max(C.City)
ELSE MAX(A.City)
END City,
A.MDate
FROM table_a A
INNER JOIN Table_B B ON A.ID = B.ID
INNER JOIN table_c C ON B.RollNo = C.RollNo
GROUP BY A.ID,A.MDate
I have those given tables:
In table2 could be multiple rows for "Kost_ID", in output these "Kost_ID" should be only one row. "MW_ID" should be in result "MW"+ number (here "MW5" and "MW6" for "MW_ID" 5+6). Hope this is clear enough.
How could I do this with sql in an oracle db? thanks
Table1
ID Kost_ID Col1
2016 1 bla
2016 2 bla
2016 3 bla1
2016 4 abl
2016 5
2016 6
2016 7
2017 2
2017 3
Table2
ID Kost_ID MW_ID Euro
2016 1 1 10
2016 2 2 20
2016 3 6 30
2016 3 5 40
2016 5 5 50
2016 6 6 60
2016 7 3 70
2016 4 4 80
Result:
ID Kost_ID Col1 MW1 MW2 MW3 MW4 MW5 MW6
2016 1 bla 10
2016 2 bla 20
2016 3 bla1 40 30
2016 4 abl 80
2016 5 50
2016 6 60
2016 7 70
If you don't want to use Pivot Queries you can try with left joins, maybe a little boring, manual and old style
select t1.*,
t21.euro mw1,t22.euro mw2, t23.euro mw3,t24.euro mw4,t25.euro mw5,t26.euro mw6
from
table1 t1 left join table2 t21
on t1.id=t21.id
and t1.kost_id=t21.kost_id
and t21.mw_id=1
left join table2 t22
on t1.id=t22.id
and t1.kost_id=t22.kost_id
and t22.mw_id=2
left join table2 t23
on t1.id=t23.id
and t1.kost_id=t23.kost_id
and t23.mw_id=3
left join table2 t24
on t1.id=t24.id
and t1.kost_id=t24.kost_id
and t24.mw_id=4
left join table2 t25
on t1.id=t25.id
and t1.kost_id=t25.kost_id
and t25.mw_id=5
left join table2 t26
on t1.id=t26.id
and t1.kost_id=t26.kost_id
and t26.mw_id=6
order by t1.id, t1.kost_id
For completness pivot solution mentioned in comments:
select *
from table1 join table2 using (id, kost_id)
pivot (sum(euro) for mw_id in (1 mw1, 2 mw2, 3 mw3, 4 mw4, 5 mw5, 6 mw6))
order by id
Test example
(sorry for the delay)
i came close but it needs some improvement.
select a.ID, a.Kost_ID,a.Col1,
case b.MW_ID when 1 then b.Euro else null end MW1,
case b.MW_ID when 2 then b.Euro else null end MW2,
case b.MW_ID when 3 then b.Euro else null end MW3,
case b.MW_ID when 4 then b.Euro else null end MW4,
case b.MW_ID when 5 then b.Euro else null end MW5,
case b.MW_ID when 6 then b.Euro else null end MW6
from table1 a join table2 b
on (a.ID=b.ID and a.Kost_ID=b.Kost_ID )
ID Kost_ID Col1 MW1 MW2 MW3 MW4 MW5 MW6
2016 1 bla 10 NULL NULL NULL NULL NULL
2016 2 bla NULL 20 NULL NULL NULL NULL
2016 3 bla1 NULL NULL NULL NULL NULL 30
2016 3 bla1 NULL NULL NULL NULL 40 NULL
2016 4 abl NULL NULL NULL 80 NULL NULL
2016 5 NULL NULL NULL NULL NULL 50 NULL
2016 6 NULL NULL NULL NULL NULL NULL 60
2016 7 NULL NULL NULL 70 NULL NULL NULL
I am having one query given below in that Employee, ShiftAllocation, ShiftMaster (two for two shift: Shift1 and shift2) table
SELECT
Em.EmployeeId, Em.EmployeeName,
Sa.ShiftAllocationDate, Sa.ShiftId2, Sa.ShiftId, Sm.ShiftName,
Sm2.ShiftName AS ShiftName2, Sa.ShiftAllocationId
FROM
ShiftAllocation AS Sa
INNER JOIN
EmployeeMaster AS Em ON Sa.EmployeeId = Em.EmployeeId
LEFT OUTER JOIN
ShiftMaster AS Sm2 ON Sa.ShiftId2 = Sm2.ShiftId
LEFT OUTER JOIN
ShiftMaster AS Sm ON Sa.ShiftId = Sm.ShiftId
I am getting this output:
ShiftAlld EmployeeId EmployeeName ShiftAllDate shiftId2 ShifId ShiftName ShiftName2
1 19 XYZ 2011-08-01 NULL 1 General NULL
2 19 XYZ 2011-08-02 NULL 1 General NULL
3 19 XYZ 2011-08-02 NULL -1 NULL NULL
4 19 XYZ 2011-08-02 NULL 1 General NULL
5 19 XYZ 2011-08-02 NULL -2 NULL NULL
6 19 XYZ 2011-08-02 NULL 1 General NULL
I want
shiftId -1 value should assign ShiftName as Week Off
ShiftId -2 value should assign ShiftName as Holiday
ShiftId2 NULL value should assign ShiftName2 as Not Assign
I want this output:
ShiftAlld EmployeeId EmployeeName ShiftAllDate shiftId2 ShifId ShiftName ShiftName2
1 19 XYZ 2011-08-01 NULL 1 General NotAssign
2 19 XYZ 2011-08-02 NULL 1 General NotAssign
3 19 XYZ 2011-08-02 NULL -1 WeekOff NotAssign
4 19 XYZ 2011-08-02 NULL 1 General NotAssign
5 19 XYZ 2011-08-02 NULL -2 Holiday NotAssign
6 19 XYZ 2011-08-02 NULL 1 General NotAssign
You can use a case something like this (untested so there may be any number of typos in there).
select Em.EmployeeId,
Em.EmployeeName,
Sa.ShiftAllocationDate,
Sa.ShiftId2,
Sa.ShiftId,
case when sa.ShiftId = -1 then 'Week Off'
when sa.ShiftId = -2 then 'Holiday'
else sm.ShiftName
end as ShiftName,
case when sm2.ShiftId is null then 'Not assigned'
else Sm2.ShiftName
end as ShiftName2,
Sa.ShiftAllocationId
from ShiftAllocation as Sa
inner join EmployeeMaster as Em
on Sa.EmployeeId = Em.EmployeeId
left outer join ShiftMaster as Sm2
on Sa.ShiftId2 = Sm2.ShiftId
left outer join ShiftMaster as Sm
on Sa.ShiftId = Sm.ShiftId
Although I am not sure if it would be the best way to do it; you can try using CASE in your sql to arrive at a solution.
Edit : This http://www.dba-oracle.com/t_case_sql_clause.htm should help you if you want to try.