SQL Server query - I can't figure it out - sql

I have a table like this : (note that id_pack is not auto incremented)
id_pack start_date end_date is_parent id_contract
1 2011-11-01 2012-01-18 1 5547
2 2012-01-18 2050-01-01 1 5547
3 2009-02-02 2050-01-01 0 5547
where id_pack = 3 is the child of the two parents. I want to make a query to select the parents and the child for the month 2012-01 but the child needs to be doubled (because his first parent finished on 2012-01-18). So the result needs to look like this :
id_pack start_date end_date id_parent
1 2012-01-01 2012-01-18 0
2 2012-01-18 2012-01-31 0
3 2012-01-01 2012-01-18 1
3 2012-01-18 2012-01-31 2
I have tried in every way and I can't figure it out. I'm doing this because parents are assigned a price rate in another table, and for the current month the child had two parents with different price rates, so I need to charge from 2012-01-01 : 2012-01-18 using a rate plan and from 2012-01-18 : 2012-01-31 using another rate plan.
Is this even possible with one query ?
Thank you
PS: I have something like this :
select c.id_pack,
case when c.start_date < '2012-01-01' then '2012-01-01'
else c.start_date
end as start_date,
case end date ...... the same as start_date as end_date,
from client a
join contract b on b.id_client = a.id_client
join package c on c.id_contract = b.id_contract
and c.start_date < dateadd(mm,1,'2012-01-01')
and c.end_date >= '2012-01-01'
where a.id_clinet = '12345'

Try:
select c.id_pack, p.start_date, p.end_date, coalesce(p.id_pack,0) id_parent
from package c
left join package p
on c.contract_id = p.contract_id and p.is_parent = 1 and c.is_parent = 0

Related

how to aggregate one record multiple times based on condition

I have a bunch of records in the table below.
product_id produced_date expired_date
123 2010-02-01 2012-05-31
234 2013-03-01 2014-08-04
345 2012-05-01 2018-02-25
... ... ...
I want the output to display how many unexpired products currently we have at the monthly level. (Say, if a product expires on August 04, we still count it in August stock)
Month n_products
2010-02-01 10
2010-03-01 12
...
2022-07-01 25
2022-08-01 15
How should I do this in Presto or Hive? Thank you!
You can use below SQL.
Here we are using case when to check if a product is expired or not(produced_date >= expired_date ), if its expired, we are summing it to get count of product that has been expired. And then group that data over expiry month.
select
TRUNC(expired_date, 'MM') expired_month,
SUM( case when produced_date >= expired_date then 1 else 0 end) n_products
from mytable
group by 1
We can use unnest and sequence functions to create a derived table; Joining our table with this derived table, should give us the desired result.
Select m.month,count(product_id) as n_products
(Select
(select x
from unnest(sequence(Min(month(produced_date)), Max(month(expired_date)), Interval '1' month)) t(x)
) as month
from table) m
left join table t on m.month >= t.produced_date and m.month <= t.expired_date
group by 1
order by 1

Count active merchants according to contract creation date and termination date for each day from 2017

So I would like to count my active partners (merchants) for each day from 2017-01-01
I have a postgresql datawarehouse where
I have a source table called sources like this:
merchantid
contract_date
termination_date
1
2018-05-28
2021-05-28
2
2018-05-27
2022-05-27
3
2018-16-14
NULL
4
2020-11-14
NULL
5
2021-03-15
NULL
6
2022-01-04
NULL
And I have a goal table called historical_active_merchants table like this:
date
num_of_merchants
...
...
2021-05-26
2021-05-27
2021-05-27
2021-05-27
2021-05-27
2021-05-27
...
...
...
... are days before and after from 2017-01-01 until now
My logic how it would be nice to work:
UPDATE historical_active_merchants SET num_of_merchants=num_of_merchants+1
WHERE (sources.contract_date <= historical_active_merchants.date
AND sources.termination_date > historical_active_merchants.date)
OR (sources.contract_date <= historical_active_merchants.date
AND sources.termination_date is null)
Is it possible without loops?
Or is there a solution by using loop?
I just can't list here all the attepmts I've tried already...
I appreciate any tips and solutions and thanks in advance!
You can update historical_active_merchants based on a select that counts the merchants.
update historical_active_merchants H
set num_of_merchants = count_merchants
from (
select H.date, count(S.merchantid) as count_merchants
from historical_active_merchants H
left join sources S on H.date >= S.contract_date
and (S.termination_date is null or H.date <= S.termination_date)
group by H.date
) X
where H.date = X.date;
(the subquery is needed because of the group by)

Finding_Missing_Dates_between_Dates_From_Data_OracleSQL

Need your assistance on finding the missing dates from records, sample below
Currently, i've data for 1, 2, 6 and 10 Jan 2020
select p.effective_date,x.xref_security_id,x.xref_type
from securitydbo.price p
inner join securitydbo.xreference x on x.security_alias = p.security_alias
where p.src_intfc_inst = 253
and p.effective_date between ('01-JAN-2020') and ('10-JAN-2020')
and x.xref_security_id = 'ABC999999999'
Expected Results
Missing_Date Xref_Security_ID Xref_Type Price
1/3/2020 ABC99999999 ISIN 0
1/7/2020 ABC99999999 ISIN 0
1/8/2020 ABC99999999 ISIN 0
1/9/2020 ABC99999999 ISIN 0
I don't have your tables so I created one which looks like result you currently have:
SQL> select * From test order by missing_date;
MISSING_DA XREF_S
---------- ------
01/03/2020 ABC999
01/07/2020 ABC999
01/08/2020 ABC999
01/09/2020 ABC999
In order to get dates that are missing, create a calendar (see the CTE I used, which is just one of row generator techniques) whose
starting date is lower date from your period
add level to it
connect by clause "loops" as many times as there are days in desired period
XREF_SECURITY_ID is NULL for missing dates as there's no match for them in your tables.
SQL> with
2 -- create a calendar for desired period (see CONNECT BY)
3 calendar as
4 (select date '2020-01-01' + level - 1 datum
5 from dual
6 connect by level <= date '2020-01-10' - date '2020-01-01' + 1
7 )
8 -- outer join calendar with your table(s)
9 select c.datum, t.xref_security_id
10 from calendar c left join test t on t.missing_date = c.datum
11 order by c.datum;
DATUM XREF_S
---------- ------
01/01/2020
01/02/2020
01/03/2020 ABC999
01/04/2020
01/05/2020
01/06/2020
01/07/2020 ABC999
01/08/2020 ABC999
01/09/2020 ABC999
01/10/2020
10 rows selected.
SQL>
I can take a guess that the date_format might be the problem out here. Without actually knowing what is the data in your tables the only way to do is to guess.
select p.effective_date,x.xref_security_id,x.xref_type
from securitydbo.price p
inner join securitydbo.xreference x on x.security_alias = p.security_alias
where p.src_intfc_inst = 253
and p.effective_date between to_date('01-JAN-2020','DD-MON-YYY')
and to_date('10-JAN-2020','DD-MON-YYYY')
and x.xref_security_id = 'ABC999999999'

Calculate SUM between two dates SQL SERVER

I'm having two tables
Calendar
FirstDate | LastDate
------------+-----------
2020-05-01 2020-05-03
2020-05-02 2020-05-04
ProfileRate
ID | Date | Rate | Product
---+------------+------+----------
1 2020-05-01 100 Prod1
2 2020-05-02 200 Prod1
3 2020-05-03 300 Prod1
4 2020-05-04 400 Prod1
5 2020-05-01 150 Prod2
6 2020-05-02 250 Prod2
7 2020-05-03 350 Prod2
8 2020-05-04 450 Prod2
I want to calculate SUM. Something like this
FirstDate | LastDate | Prod1 | Prod2
------------+-------------+--------+-------
2020-05-01 2020-05-03 600 750
2020-05-02 2020-05-04 900 1050
What I've tried:
SELECT [Date], SUM([Rate])
FROM [ProfileRate]
WHERE [Date] BETWEEN '2020-05-01' AND '2020-05-04'
GROUP BY [Date]
Please help me. Thanks
you have to do several steps to solve the problem:
combine calendar records with profiles
establish which profiles meet the calendar range
total the value for each profile and date range
finally establish the detailed information of the calendar
this query meets the conditions
with DataForCalendar as
(
SELECT IdCalendar,FirstDate,LastDate,Id,DateRate,Rate,Product
FROM
Calendar CROSS JOIN ProfileRate
where DateRate between '2020-05-01' and '2020-05-05'
),
DetailForCalendar as
(
select IdCalendar,Rate,Product
from DataForCalendar
where DateRate between FirstDate and LastDate
),
TotalForCalendar as
(
select IdCalendar,Product,sum(Rate)As Total from DetailForCalendar
GROUP BY IdCalendar,Product
)
select Calendar.IdCalendar,Calendar.FirstDate,Calendar.LastDate,
TotalForCalendar.Product,TotalForCalendar.Total
from TotalForCalendar inner join
Calendar on TotalForCalendar.IdCalendar=Calendar.IdCalendar;
in this example you can find step by step how it work
in this example there is one more product and one more calendar.
I think this is a JOIN and conditional aggregation:
SELECT c.FirstDate, c.LastDate,
SUM(CASE WHEN pr.prod = 'Prod1' THEN pr.Rate END) as prod1,
SUM(CASE WHEN pr.prod = 'Prod2' THEN pr.Rate END) as prod2
FROM Calender c LEFT JOIN
ProfileRate pr
ON pr.Date >= c.FirstDate AND pr.Date <= c.LastDate
GROUP BY c.FirstDate, c.LastDate;
Do the join & conditional aggregation :
select c.fisrtdate, c.lastdate,
sum(case when pr.product = 'prod1' then rate else 0 end) as prod1,
sum(case when pr.product = 'prod2' then rate else 0 end) as prod2
from calendar c join
ProfileRate pr
on pr.date >= c.fisrtdate and pr.date <= c.lastdate
group by c.fisrtdate, c.lastdate;
If you want all calendar dates then use left join instead.

sql query : double record for joins ... can;t figure it out

I have some tables like this :
I. parent table :
id_client id_group package start_date end_date id_contract is_parent
1223 88 1234 2012-01-01 2050-01-01 156447 1
1223 89 34342 2011-04-01 2050-01-01 156447 1
II. share table :
id package id_share
1 1234 SS4433 - parent
2 564679 SS4433 --- this is a child
3 564522 SS4433 -- this is a child
4 34342 SS2345 - parent
5 665456 SS2345 -- child
6 7789997 SS2345 -- child
III. child table :
package start_date end_date id_contract
564679 2011-01-01 2012-02-01 156447
564522 2011-01-01 2011-05-07 156447
665456 2011-01-01 2012-02-04 156447
7789997 2011-01-01 2011-07-03 156447
The question is how to select with one query the parent and all it's children in the same select (based on id_share in share table), that contains the group of the parent.
The result should look like this:
id_client id_group package start_date end_date id_contract child_of
1223 88 1234 2012-01-01 2050-.. 156447 0
1223 88 564679 2011-01-01 2012-02-01 156447 1234
1223 89 34342 2011-04-01 2050-... 156447 0
1223 89 665456 2011-01-01 2012-02-04 156447 34342
I have tried in every way .. but I can't figure it out how to do it .. without union all
I have tried this :
select a.id_client, a.id_group, ??package?? , id_contract , ??child_of??
from parent_table a
join share_table b on b.package = a.package
join share_table c on c.id_share = b.id_share
join child_table d on d.package = c.package
PS: I need to find parents and childs that corespond to 2012-01-01 - 2012-01-31 interval
where i have put ?? i don;t know .
Thanks
UPDATED, to restrict parents and children by date:
select a.id_client,
a.id_group,
coalesce(d.package, a.package) package,
coalesce(d.start_date, a.start_date) start_date,
coalesce(d.end_date, a.end_date) end_date,
coalesce(d.id_contract, a.id_contract) id_contract,
case when d.package is not null then a.package else 0 end child_of
from parent_table a
join share_table b on b.package = a.package
join share_table c on c.id_share = b.id_share
left join child_table d on d.package = c.package and
d.start_date <= '2012-01-31' and
d.end_date >= '2012-01-01'
where a.start_date <= '2012-01-31' and
a.end_date >= '2012-01-01' and
(d.package is not null or a.package = c.package)
How about this.
select p.id_client, p.id_group, s.package, c.start_date, c.id_contract
from parent p right outer join share s
on p.package = s.package
right outer join child c
on p.package = c.package;
A union seems a nicer way to go but it is possible using isnull and outer joins...
select isnull(p.id_client, pofc.id_client) id_client, isnull(p.id_group, pofc.id_group) id_group, isnull(p.package, c.package) package, isnull(p.startDate, c.startDate), isnull(p.endDate, c.endDate) endDate, isnull(p.id_contract, c.id_contract) id_contract, isnull(pofc.package, 0) child_of
from share s
left outer join parent p on p.package = s.package and p.startDate <= #toDate and p.endDate >= #fromDate
left outer join child c on c.package = s.package and c.startDate <= #toDate and c.endDate >= #fromDate
left outer join (select ps.id_share, p.package, p.id_client, p.id_group from share ps inner join parent p on p.package = ps.package) pofc on pofc.id_share = s.share and pofc.package <> s.package
where p.package is not null
or c.package is not null