How do I Separate One Column values into Multiple rows based on condition in SQL - sql

How to Seperate column values into multiple rows based on Condition. Resultant table will show in Grid view. I tried with Count(*) in multiple select statements but not what i expected. Thanks in advance
Table: RegistrationReport
Date Type
-----------------------------------------
02/05/2015 A
04/05/2015 B
04/05/2015 C
05/05/2015 A
I need output like this:
Date Type 1 Type 2 Type 3
--------------------------------------------------
02/05/2015 A - -
04/05/2015 - B -
04/05/2015 - - C
05/05/2015 A - -
--------------------------------------------------
Total: 2 1 1

Try below mentioned simple query to get Total as well.
;with CTE as(
SELECT Date
,case when Type = 'A' then 'A' else '-' end as 'Type_1'
, case when Type = 'B' then 'B' else '-' end as 'Type_2'
, case when Type = 'C' then 'C' else '-' end as 'Type_3'
FROM RegistrationReport
)
select cast(Date as varchar(20))Date
,Type_1
,Type_2
,Type_3
from CTE
UNION ALL
SELECT 'Total:'
,CAST(SUM(case when Type_1= 'A' then 1 else 0 end)as varchar(10))
,CAST(SUM(case when Type_2= 'B' then 1 else 0 end)as varchar(10))
,CAST(SUM(case when Type_3= 'C' then 1 else 0 end) as varchar(10))
FROM CTE
You will get required output!

Assuming you know the number of columns, and it is relatively few, I think the easiest solution is to just self join:
Select distinct Cast(coalesce(a.date, b.date, c.date) as varchar) as Date
, isnull(a.Type, '--') as Type1
, isnull(b.Type, '--') as Type2
, isnull(c.Type, '--') as Type3
from Table a
full outer join Table b
on a.date = b.date
full outer join Table c
on isnull(a.date, b.date) = c.date
where isnull(a.type, 'A') = 'A'
and isnull(b.type, 'B') = 'B'
and isnull(c.type, 'C') = 'C'
union all
select 'Total'
, count(distinct case when type = 'A' then Date end)
, count(distinct case when type = 'B' then Date end)
, count(distinct case when type = 'C' then Date end)
from Table

Related

Sql optimization query with join on Presto

I have the following query which shows out of all the clicks on products how many no of products have >1 image. The queries separately work fine but when combined its not able to execute within 3m threshold time. Any inputs how can this be optimized best.
select DATE (DATE_TRUNC('week',dt)) AS wk_dt,COUNT(DISTINCT a.product_id) tot_prods,COUNT(DISTINCT b.product_id) multiimp_prods,count(a.product_id) AS total_clicks,count(case when b.product_id>0 then a.product_id END) AS total_mulimg_clicks
from (
select product_id,DATE(from_unixtime((time/1000)+19800)) as dt--,count(distinct_id) clicks
from silver.mixpanel_android__product_clicked
WHERE DATE(from_unixtime((time/1000)+19800)) BETWEEN date(date_trunc('week',cast(Current_date - interval '14' day AS date))) AND Current_date
GROUP BY 1,2) a --2,471,245 1,458,476
LEFT join (
SELECT product_id,tot_img
FROM (SELECT DISTINCT product_id, catalog_id,(a + b + c + d + e) AS tot_img
FROM (
SELECT product_id,catalog_id,
CASE WHEN images is NULL then 0 else 1 end as a,
CASE WHEN img_2 is NULL then 0 else 1 end as b,
CASE WHEN img_3 is NULL then 0 else 1 end as c,
CASE WHEN img_4 is NULL then 0 else 1 end as d,
CASE WHEN img_5 is NULL then 0 else 1 end as e
FROM (
SELECT DISTINCT id AS product_id,catalog_id,
TRIM(images) AS images,
TRIM(SPLIT_PART(images,',',2)) AS "img_2",
TRIM(SPLIT_PART(images,',',3)) AS "img_3",
TRIM(SPLIT_PART(images,',',4)) AS "img_4",
TRIM(SPLIT_PART(images,',',5)) AS "img_5"
FROM silver.supply__products --WHERE date(created) <= date(date_trunc('week',cast(Current_date - interval '14' day AS date)))
)
--GROUP BY 1,2
order by 6 asc
)
)
WHERE tot_img>1
) b
on a.product_id=b.product_id
GROUP BY 1

How can I make two column from same table by two query

I've two query from same table but by two condition but how can I make two column for this two conditional count.
SELECT Count(*) FROM TBL_FT WHERE STATUS = 'X';
SELECT Count(*) FROM TBL_FT WHERE STATUS = 'Y' and
LOGDATE>trunc(sysdate);
You can use conditional aggregation:
SELECT
COUNT(CASE WHEN STATUS = 'X' THEN 1 END),
COUNT(CASE WHEN STATUS = 'Y' AND LOGDATE > trunc(sysdate) THEN 1 END)
FROM TBL_FT
You can also add a WHERE clause:
WHERE STATUS IN ('X', 'Y');
you can use something like this -
SELECT SUM(CASE
WHEN STATUS = 'X' THEN
1
ELSE
0
END) FIRST_VAL,
SUM(CASE
WHEN STATUS = 'Y'
AND LOGDATE > TRUNC(SYSDATE) THEN
1
ELSE
0
END) second_val
FROM TBL_FT;

SQL: Trying to understand IF/ELSE

SELECT CASE r.SourceId
WHEN '1' THEN 'ITUNES'
WHEN '2' THEN 'SFR'
WHEN '3' THEN 'ORANGE'
ELSE 'Others'
END as source
, CAST(SUM (r.SalesVolume) AS DECIMAL(14, 4) ) AS Volume
, CAST(SUM (r.SalesVolume * r.CustomerPrice) AS DECIMAL(14, 4) ) AS Value
from Rawdata r
INNER JOIN Product p
ON p.ProductId = r.ProductId
INNER JOIN Calendar c
ON r.DayId = c.DayId
WHERE c.WeekId BETWEEN (20145227) AND (20155230)
AND p.ContentFlavor IN ('SD', 'HD')
AND p.VODEST IN ('VOD','EST')
AND p.Distributor IN ('M6SND')
GROUP BY CASE r.SourceId
WHEN '1' THEN 'ITUNES'
WHEN '2' THEN 'SFR'
WHEN '3' THEN 'ORANGE'
ELSE 'Others'
END
The result of the above query is:
source Volume Value
ITUNES 48316.0000 506067.2600
This result is perfectly OK since my source table RawData doesnt contain any values for SourceId 2 or 3.
But what I basically want is the result to look like is:
source Volume Value
ITUNES 48316.0000 506067.2600
SFR 0 0
ORANGE 0 0
Others 0 0
If there is no value corresponding to any column parameter then I need it to be 0
I assume this could be done using IF/ELSE but not sure how?
with the help of a CTE this is a way to do it. (replace the first query with something more dynamic if you want)
with myChoices (choices)
as (
select
choices
from (
values
('ITUNES'),
('SFR'),
('ORANGE'),
('Others')
) [ ] (choices)
),
myQuery ([source],[Volume],[Value])
as (
SELECT CASE r.SourceId
WHEN '1' THEN 'ITUNES'
WHEN '2' THEN 'SFR'
WHEN '3' THEN 'ORANGE'
ELSE 'Others'
END as source
, CAST(SUM (r.SalesVolume) AS DECIMAL(14, 4) ) AS Volume
, CAST(SUM (r.SalesVolume * r.CustomerPrice) AS DECIMAL(14, 4) ) AS Value
from Rawdata r
INNER JOIN Product p
ON p.ProductId = r.ProductId
INNER JOIN Calendar c
ON r.DayId = c.DayId
WHERE c.WeekId BETWEEN (20145227) AND (20155230)
AND p.ContentFlavor IN ('SD', 'HD')
AND p.VODEST IN ('VOD','EST')
AND p.Distributor IN ('M6SND')
GROUP BY CASE r.SourceId
WHEN '1' THEN 'ITUNES'
WHEN '2' THEN 'SFR'
WHEN '3' THEN 'ORANGE'
ELSE 'Others'
END
)
select
c.choices,
ISNULL(q.Volume,0)Volume,
ISNULL(q.Value,0)Value
from myChoices c
left join myQuery q on
c.choices = q.[source]
Create an inline view called "Product_Inline_View", which is like
(select 1 as SourceId, 'ITUNES' as source_name
union all
select 2 as SourceId, 'SFR' as source_name
union all
select 3 as SourceId, 'ORANGE' as source_name
)
Right Join the Product_Inline_view with the Query you have, but without the CASE.
And then do the group by.

ORACLE SQL: Fill in missing dates

I have the following code which gives me production dates and production volumes for a thirty day period.
select
(case when trunc(so.revised_due_date) <= trunc(sysdate)
then trunc(sysdate) else trunc(so.revised_due_date) end) due_date,
(case
when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD')
then 'CD' end) = 'CD'
and (case when so.tec_criteria in ('PI','MC')
then 'XX' else so.tec_criteria end) = 'OF'
then sum(so.revised_qty_due)
end) CD_OF_VOLUME
from shop_order so
left join scm_prodtyp sp
on so.prodtyp = sp.prodtyp
where so.order_type = 'MD'
and so.plant = 'W'
and so.status_code between '4' and '8'
and trunc(so.revised_due_date) <= trunc(sysdate)+30
group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
order by trunc(so.revised_due_date)
The problem I have is where there is a date with no production planned, the date wont appear on the report. Is there a way of filling in the missing dates.
i.e. the current report shows the following ...
DUE_DATE CD_OF_VOLUME
14/04/2015 35,267.00
15/04/2015 71,744.00
16/04/2015 20,268.00
17/04/2015 35,156.00
18/04/2015 74,395.00
19/04/2015 3,636.00
21/04/2015 5,522.00
22/04/2015 15,502.00
04/05/2015 10,082.00
Note: missing dates (20/04/2015, 23/04/2015 to 03/05/2015)
Range is always for a thirty day period from sysdate.
How do you fill in the missing dates?
Do you need some kind of calendar table?
Thanks
You can get the 30-day period from SYSDATE as follows (I assume you want to include SYSDATE?):
WITH mydates AS (
SELECT TRUNC(SYSDATE) - 1 + LEVEL AS due_date FROM dual
CONNECT BY LEVEL <= 31
)
Then use the above to do a LEFT JOIN with your query (perhaps not a bad idea to put your query in a CTE as well):
WITH mydates AS (
SELECT TRUNC(SYSDATE) - 1 + LEVEL AS due_date FROM dual
CONNECT BY LEVEL <= 31
), myorders AS (
select
(case when trunc(so.revised_due_date) <= trunc(sysdate)
then trunc(sysdate) else trunc(so.revised_due_date) end) due_date,
(case
when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD')
then 'CD' end) = 'CD'
and (case when so.tec_criteria in ('PI','MC')
then 'XX' else so.tec_criteria end) = 'OF'
then sum(so.revised_qty_due)
end) CD_OF_VOLUME
from shop_order so
left join scm_prodtyp sp
on so.prodtyp = sp.prodtyp
where so.order_type = 'MD'
and so.plant = 'W'
and so.status_code between '4' and '8'
and trunc(so.revised_due_date) <= trunc(sysdate)+30
group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
order by trunc(so.revised_due_date)
)
SELECT mydates.due_date, myorders.cd_of_volume
FROM mydates LEFT JOIN myorders
ON mydates.due_date = myorders.due_date;
If you want to show a zero on "missing" dates instead of a NULL, use COALESCE(myorders.cd_of_volume, 0) AS cd_of_volume above.
what you can do is this :
creating a new table with all the days you need .
WITH DAYS AS
(SELECT TRUNC(SYSDATE) - ROWNUM DDD
FROM ALL_OBJECTS
WHERE ROWNUM < 365)
SELECT
DAYS.DDD
FROM
DAYS;
then full outer join between thoes table :
select DUE_DATE , CD_OF_VOLUME , DDD
from (
select
(case when trunc(so.revised_due_date) <= trunc(sysdate)
then trunc(sysdate) else trunc(so.revised_due_date) end) due_date,
(case
when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD')
then 'CD' end) = 'CD'
and (case when so.tec_criteria in ('PI','MC')
then 'XX' else so.tec_criteria end) = 'OF'
then sum(so.revised_qty_due)
end) CD_OF_VOLUME
from shop_order so
left join scm_prodtyp sp
on so.prodtyp = sp.prodtyp
where so.order_type = 'MD'
and so.plant = 'W'
and so.status_code between '4' and '8'
and trunc(so.revised_due_date) <= trunc(sysdate)+30
group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
order by trunc(so.revised_due_date)
) full outer join NEW_TABLE new on ( new .DDD = DUE_DATE )
where new .DDD between /* */ AND /* */ /* pick your own limit) */
you can get the gaps by using connect by and a left join:
assuming your schema is:
create table tbl(DUE_DATE date, CD_OF_VOLUME float);
insert into tbl values(to_date('14/04/2015','DD/MM/YYYY'),35267.00);
insert into tbl values(to_date('15/04/2015','DD/MM/YYYY'),71744.00);
insert into tbl values(to_date('16/04/2015','DD/MM/YYYY'),20268.00);
insert into tbl values(to_date('17/04/2015','DD/MM/YYYY'),35156.00);
insert into tbl values(to_date('18/04/2015','DD/MM/YYYY'),74395.00);
insert into tbl values(to_date('19/04/2015','DD/MM/YYYY'),3636.00);
insert into tbl values(to_date('21/04/2015','DD/MM/YYYY'),5522.00);
insert into tbl values(to_date('22/04/2015','DD/MM/YYYY'),15502.00);
insert into tbl values(to_date('04/05/2015','DD/MM/YYYY'),10082.00);
you can say:
with cte as
(
select (select min(DUE_DATE)-1 from tbl)+ level as dt
from dual
connect by level <= (select max(DUE_DATE)-min(DUE_DATE) from tbl)
)
select to_char(c.dt,'DD/MM/YYYY') gap,null volume
from cte c
left join tbl t on c.dt=t.DUE_DATE
where t.DUE_DATE is null
order by c.dt
Result:
GAP VOLUME
20/04/2015 (null)
23/04/2015 (null)
24/04/2015 (null)
25/04/2015 (null)
26/04/2015 (null)
27/04/2015 (null)
28/04/2015 (null)
29/04/2015 (null)
30/04/2015 (null)
01/05/2015 (null)
02/05/2015 (null)
03/05/2015 (null)
Notice: you can implement this in your original query, one simplest way is to wrap your query and use it as a subquery instead of tbl in above code snippet.

Oracle view creation

I have a case like in the below picture
.
In the input table, each value under name column should have five steps A,B,C,D,E....But the name "VINOD" has 3 values A,B,C and their corresponding dates are 28.12.2013,11.10.2013 and NULL. So, in the view, i should have five diffrenet columns for each name as below. Since, "Vinod" does not have D and E, the corresponding dates should be seens NA( but since C value is NULL in table, it should be viewed as NULL only).
Hope i explained my query. Kindly help me.
Thanks in advance.
You shouldn't mix data types like that.
Using the following test case:
-- drop table input_table;
create table input_table(
name varchar2(20) not null
,step varchar2(10) not null
,step_date varchar2(10)
);
insert into input_table(name, step, step_date) values('VINOD', 'A', '28.12.013');
insert into input_table(name, step, step_date) values('VINOD', 'B', '11.10.2013');
insert into input_table(name, step, step_date) values('VINOD', 'C', null);
commit;
The following (horrible) query should do what you ask for:
select name
-- If a row exists (has flag) pick whatever value was there, otherwise set NA
,case when max(a_flag) = 'A' then max(a_date) else 'NA' end as a_date
,case when max(b_flag) = 'B' then max(b_date) else 'NA' end as b_date
,case when max(c_flag) = 'C' then max(c_date) else 'NA' end as c_date
,case when max(d_flag) = 'D' then max(d_date) else 'NA' end as d_date
,case when max(e_flag) = 'E' then max(e_date) else 'NA' end as e_date
from (select name
-- Pivot the dates to columns
,case when step = 'A' then step_date end as a_date
,case when step = 'B' then step_date end as b_date
,case when step = 'C' then step_date end as c_date
,case when step = 'D' then step_date end as d_date
,case when step = 'E' then step_date end as e_date
-- Create flags because we have two kinds of NULL...
,case when step = 'A' then 'A' end as a_flag
,case when step = 'B' then 'B' end as b_flag
,case when step = 'C' then 'C' end as c_flag
,case when step = 'D' then 'D' end as d_flag
,case when step = 'E' then 'E' end as e_flag
from input_table
)
group
by name;
You could try:
SELECT name,
(CASE WHEN A_DATE IS NULL THEN 'NA' ELSE A_DATE END) as A_DATE,
(CASE WHEN B_DATE IS NULL THEN 'NA' ELSE B_DATE END) as B_DATE,
(CASE WHEN C_DATE IS NULL THEN 'NA' ELSE C_DATE END) as C_DATE,
(CASE WHEN D_DATE IS NULL THEN 'NA' ELSE D_DATE END) as D_DATE,
(CASE WHEN E_DATE IS NULL THEN 'NA' ELSE E_DATE END) as E_DATE
FROM (
SELECT name,
(SELECT date
FROM inputtable as i2
WHERE i2.name=i1.name
AND i2.step = 'A') as A_DATE,
(SELECT date
FROM inputtable as i3
WHERE i3.name=i1.name
AND i3.step = 'B') as B_DATE,
(SELECT date
FROM inputtable as i4
WHERE i4.name=i1.name
AND i4.step = 'C') as C_DATE,
(SELECT date
FROM inputtable as i5
WHERE i5.name=i1.name
AND i5.step = 'D') as D_DATE,
(SELECT date
FROM inputtable as i6
WHERE i6.name=i1.name
AND i6.step = 'E') as E_DATE
FROM inputtable as i1
GROUP BY name
) s1