expected result is not getting - sql

I have a data like this:
And I want this - I am trying with PIVOT but not getting the expected results:
Query is
SELECT AttendeeID,[Quantity1],[PROD1],[Quantity2],[PROD2],[Quantity3],[PROD3] FROM
(SELECT * ,
row_number() over(partition by AttendeeID order by AttendeeID)rn
from #ProductTestingwithPosition2) TT
PIVOT
(MAX(product) for ProductPosition in ([PROD1],[PROD2],[PROD3])) AS Tab2
PIVOT
(sum(Quantity) for QuantityPosition in ([Quantity1],[Quantity2],[Quantity3])) AS Tab3
I am getting this output:

Just use conditional aggregation:
SELECT AttendeeID,
MAX(CASE WHEN ProductPosition = 'PROD1' THEN product END) as prod1,
MAX(CASE WHEN QuantityPosition = 'QUANTITY1' THEN quantity END) as quantity1,
MAX(CASE WHEN ProductPosition = 'PROD2' THEN product END) as prod2,
MAX(CASE WHEN QuantityPosition = 'QUANTITY2' THEN quantity END) as quantity2,
MAX(CASE WHEN ProductPosition = 'PROD3' THEN product END) as prod3,
MAX(CASE WHEN QuantityPosition = 'QUANTITY3' THEN quantity END) as quantity3
FROM (SELECT ptp.* ,
row_number() over (partition by AttendeeID, ProductPosition order by AttendeeID) as seqnum
FROM #ProductTestingwithPosition2 ptp
) ptp
GROUP BY AttendeeID, seqnum;
PIVOT -- in addition to being non-standard -- is very finicky. Conditional aggregation is much more powerful and less prone to errors.

Related

How to get multiple columns in Crosstab

I would like a cross table from the following table.
The cross table should look like this
A pivot table does not seem to solve the problem, because only one column can be used at a time. But in our case we are dealing with 4 different columns. (payment, month, year and free of charge)
I solved the problem by splitting these 4 columns into four different pivot tables, using temporary tables and finally reassembling the obtained data. But this is very complicated, long and confusing, in short not very nice...
The years and months should be shown in ascending form, exactly as you can see in the cross table above.
I have been looking for a solution for quite a while but I can't find the same problem anywhere.
If someone would give me a short, elegant solution I would be very grateful.
Under http://www.sqlfiddle.com/#!18/7216f/2 you can see the problem definition.
Thank you!
You can rank records by date in a subquery with row_number(), and then pivot with conditional aggregation:
select
ClientId,
max(case when rn = 1 then Payment end) Payment1,
max(case when rn = 2 then Payment end) Payment2,
max(case when rn = 3 then Payment end) Payment3,
max(case when rn = 1 then [Month] end) Month1,
max(case when rn = 2 then [Month] end) Month2,
max(case when rn = 3 then [Month] end) Month3,
max(case when rn = 1 then [Year] end) Year1,
max(case when rn = 2 then [Year] end) Year2,
max(case when rn = 3 then [Year] end) Year3,
max(case when rn = 1 then FreeOfCharge end) FreeOfCharge1,
max(case when rn = 2 then FreeOfCharge end) FreeOfCharge2,
max(case when rn = 3 then FreeOfCharge end) FreeOfCharge3
from (
select
t.*,
row_number() over(partition by ClientId order by [Year], [Month]) rn
from mytable t
) t
group by ClientId
You can join the table with itself a few times, as in:
with p as (
select
*, row_number() over(partition by clientid order by year, month) as n
from Payment
)
select
p1.clientid,
p1.payment, p2.payment, p3.payment,
p1.month, p2.month, p3.month,
p1.year, p2.year, p3.year,
p1.freeofcharge, p2.freeofcharge, p3.freeofcharge
from p p1
left join p p2 on p2.clientid = p1.clientid and p2.n = 2
left join p p3 on p3.clientid = p1.clientid and p3.n = 3
where p1.n = 1
See Fiddle.

Hive rolling sum of data over date

I am working on Hive and am facing an issue with rolling counts. The sample data I am working on is as shown below:
and the output I am expecting is as shown below:
I tried using the following query but it is not returning the rolling count:
select event_dt,status, count(distinct account) from
(select *, row_number() over (partition by account order by event_dt
desc)
as rnum from table.A
where event_dt between '2018-05-02' and '2018-05-04') x where rnum =1
group by event_dt, status;
Please help me with this if some one has solved a similar issue.
You seem to just want conditional aggregation:
select event_dt,
sum(case when status = 'Registered' then 1 else 0 end) as registered,
sum(case when status = 'active_acct' then 1 else 0 end) as active_acct,
sum(case when status = 'suspended' then 1 else 0 end) as suspended,
sum(case when status = 'reactive' then 1 else 0 end) as reactive
from table.A
group by event_dt
order by event_dt;
EDIT:
This is a tricky problem. The solution I've come up with does a cross-product of dates and users and then calculates the most recent status as of each date.
So:
select a.event_dt,
sum(case when aa.status = 'Registered' then 1 else 0 end) as registered,
sum(case when aa.status = 'active_acct' then 1 else 0 end) as active_acct,
sum(case when aa.status = 'suspended' then 1 else 0 end) as suspended,
sum(case when aa.status = 'reactive' then 1 else 0 end) as reactive
from (select d.event_dt, ac.account, a.status,
max(case when a.status is not null then a.timestamp end) over (partition by ac.account order by d.event_dt) as last_status_timestamp
from (select distinct event_dt from table.A) d cross join
(select distinct account from table.A) ac left join
(select a.*,
row_number() over (partition by account, event_dt order by timestamp desc) as seqnum
from table.A a
) a
on a.event_dt = d.event_dt and
a.account = ac.account and
a.seqnum = 1 -- get the last one on the date
) a left join
table.A aa
on aa.timestamp = a.last_status_timestamp and
aa.account = a.account
group by d.event_dt
order by d.event_dt;
What this is doing is creating a derived table with rows for all accounts and dates. This has the status on certain days, but not all days.
The cumulative max for last_status_timestamp calculates the most recent timestamp that has a valid status. This is then joined back to the table to get the status on that date. Voila! This is the status used for the conditional aggregation.
The cumulative max and join is a work-around because Hive does not (yet?) support the ignore nulls option in lag().

Aggregation disables window function capability

I am trying to re-write the query where I am joining the query on itself:
select count(distinct case when cancelled_client_id is null and year(RUM.first_date) = year(date) and RUM.first_date <= .date then user_id
when cancelled_client_id is null and year(coalesce(RUM.first_date,RUR.first_date)) = year(date)
and coalesce(RUM.first_date,RUR.first_date) <= RUL.date then user_id end) as
from RUL
left join
(
select enrolled_client_id, min(date) as first_date
from RUL
where enrolled_client_id is not null
group by enrolled_client_id
) RUR on RUR.enrolled_client_id=RUL.enrolled_client_id
left join
(
select managed_client_id, min(date) as first_date
from RUL
where managed_client_id is not null
group by managed_client_id
) RUM on RUM.managed_client_id=RUL.managed_client_id
Using window functions:
count(distinct case when cancelled_client_id is null
and year(min(case when enrolled_client_id is not null then date end) over(partition by enrolled_client_id)) = year(date)
and min(case when enrolled_client_id is not null then date end) over(partition by enrolled_client_id) <= date
then user_id
when cancelled_client_id_rev is null
and year(coalesce(
min(case when enrolled_client_id is not null then date end) over(partition by enrolled_client_id),
min(case when managed_client_id is not null then date end) over(partition by managed_client_id))) = year(date)
and coalesce(
min(case when enrolled_client_id is not null then date end) over(partition by enrolled_client_id),
min(case when managed_client_id is not null then date end) over(partition by managed_client_id)) <= date
then user_id end)
from RUL
However I am getting an error that "Windowed functions cannot be used in the context of another windowed function or aggregate" due to the count(distinct min). Any work-arounds?
I have no idea what the count(distinct) is supposed to be doing, but you can simplify the code to:
select count(distinct case when cancelled_client_id is null and
year(rum_first_date) = year(date) and
rum_first_date <= rul.date
then user_id
when cancelled_client_id is null and
year(coalesce(RUM_first_date, RUR_first_date)) = year(rul.date) and
coalesce(rum_first_date, rur_first_date) <= RUL.date
then user_id
end) as . . .
from (select RUL.*,
min(date) over (partition by enrolled_client_id) as rur_date,
min(date) over (partition by managed_client_id) as rum_date
from RUL
) RUL

Cross Tab Report Oracle SQL

mytable:
and result i want:
but i can't query do you help me?
As I understand your requirement you want pivoting of your data.
Try this:
select tmn_code,
max(case when bank_type=1 then totalamount end) as bank_1_total_amount,
max(case when bank_type=1 then totalpay end) as bank_1_totalpay,
max(case when bank_type=2 then totalamount end) as bank_2_total_amount,
max(case when bank_type=2 then totalpay end) as bank_2_totalpay
from your_table group by tmn_code;

Return the First, Second and Third Earliest Purchase Dates per Purchaser

for a list of purchaser email addresses, I am trying to return one line per purchaser that has the columns '1stOrderDate', '2ndOrderDate', '3rdOrderDate' and 'TotalNumberofOrders'
I have tried using the ROW_Number function in the WHERE clause of subqueries but it reports that Windowed functions aren't allowed in the WHERE clause, so any help on how I fill in the ???s below would be gratefully received!
SELECT
PT.email AS 'Email',
MIN(OT.orderdate) AS '1stOrderDate',
??? AS '2ndOrderDate',
??? AS '3rdOrderDate',
COUNT(DISTINCT OT.order_reference) AS 'TotalNumberOfOrders'
FROM dbo.Orders AS OT
JOIN dbo.Purchaser AS PT ON OT.account_reference = PT.account_reference
GROUP BY PT.Email
You can do this with row_number() and conditional aggregation:
SELECT PT.email,
MAX(CASE WHEN seqnum = 1 THEN OT.OrderDate END) as OrderDate_1,
MAX(CASE WHEN seqnum = 2 THEN OT.OrderDate END) as OrderDate_2,
MAX(CASE WHEN seqnum = 3 THEN OT.OrderDate END) as OrderDate_3,
COUNT(DISTINCT OT.order_reference) AS TotalNumberOfOrders
FROM (SELECT o.*, ROW_NUMBER() OVER (PARTITION BY account_reference ORDER BY o.orderdate) as seqnum
FROM dbo.Orders o
) OT JOIN
dbo.Purchaser PT
ON OT.account_reference = PT.account_reference
GROUP BY PT.Email
A couple of notes:
Don't use single quotes for column aliases. Instead, choose column names that do not require escaping.
For the segnum = 1 logic, you can use MIN(), but I think consistency is a benefit here.
EDIT:
My guess is that the problem is the difference between a account_reference and email. Try this:
SELECT email,
MAX(CASE WHEN seqnum = 1 THEN OT.OrderDate END) as OrderDate_1,
MAX(CASE WHEN seqnum = 2 THEN OT.OrderDate END) as OrderDate_2,
MAX(CASE WHEN seqnum = 3 THEN OT.OrderDate END) as OrderDate_3,
COUNT(DISTINCT OT.order_reference) AS TotalNumberOfOrders
FROM (SELECT o.*, ROW_NUMBER() OVER (PARTITION BY pt.email ORDER BY o.orderdate) as seqnum
FROM dbo.Orders o JOIN
dbo.Purchaser PT
ON OT.account_reference = PT.account_reference
) OT
GROUP BY PT.Email