Thanks for all your suggestions.It works fine on a small test data but I guess I under-estimated the total rows and plans so I guess I will have to post some biggers sample data
Here it is:
CREATE TABLE MasterTable
(`Date` datetime, `PhNO` int, `Plan_name` varchar(13), `Plan_price` varchar(3))
;
INSERT INTO MasterTable
(`Date`, `PhNO`, `Plan_name`, `Plan_price`)
VALUES
('2014-01-01 13:00:00', 3232222, 'Basepack1', '$32'),
('2014-01-01 13:00:00', 3232222, 'Basepack2', '$31'),
('2014-01-01 13:00:00', 3221111, 'Basepack6', '$21'),
('2014-01-01 13:00:00', 543222, 'BaseValuePack', '$76'),
('2014-01-01 13:00:00', 543222, 'Basepack1', '$30'),
('2014-01-01 13:00:00', 32322221, 'Basepack1', '$37'),
('2014-01-01 13:00:00', 32322221, 'Basepack2', '$21'),
('2014-01-01 13:00:00', 32322354, 'Basepack7', '$23'),
('2014-01-01 13:00:00', 32322254, 'Basepack8', '$11'),
('2014-01-01 13:00:00', 3267767, 'Non-base1', '$21'),
('2014-01-01 13:00:00', 3267762, 'Non-base1', '$21'),
('2014-01-01 13:00:00', 32677676, 'Non-base3', '$76'),
('2014-01-01 13:00:00', 5267767, 'Non-base9', '$21')
Now I basically want to group all the 'Non-base%' plans under 'Casual' category
Here is the desired output:
Date Plan_name Phone_no_count
'2014-01-01 13:00:00' 'Basepack1' 2
'2014-01-01 13:00:00' 'Basepack2' 0
'2014-01-01 13:00:00' 'Basepack6' 1
'2014-01-01 13:00:00' 'BaseValuepack' 1
'2014-01-01 13:00:00' 'Casual' 4
Thanks
...........................................
Previous request:
I need to count all the phone nos categorised by certain plans. But to group those plans, I need to rank them first based on their price.
Here is the ddl
CREATE TABLE MasterTable
(`Date` datetime, `PhNO` int, `Plan_name` varchar(13), `Plan_price` varchar(3))
;
INSERT INTO MasterTable
(`Date`, `PhNO`, `Plan_name`, `Plan_price`)
VALUES
('2014-01-01 13:00:00', 3232222, 'Basepack1', '$32'),
('2014-01-01 13:00:00', 3232222, 'Basepack2', '$31'),
('2014-01-01 13:00:00', 3221111, 'Basepack6', '$21'),
('2014-01-01 13:00:00', 543222, 'BaseValuePack', '$76'),
('2014-01-01 13:00:00', 543222, 'Basepack1', '$30'),
('2014-01-01 13:00:00', 32322221, 'Basepack1', '$37'),
('2014-01-01 13:00:00', 32322221, 'Basepack2', '$21')
;
Now the rule is, I only need to count a phone no once who has more than 1 plan based on their plan price(higher one) .
But there is also a scenario where a phone no has two different 'packs'- Basepack and valuepack, which means I need to count that phone no only once categorised under value pack(in this case we need to ignore the price).
Here is the desired output.
Date Plan_name Phone_no_count
-------------------------------------------------
'2014-01-01 13:00:00' 'Basepack1' 2
'2014-01-01 13:00:00' 'Basepack2' 0
'2014-01-01 13:00:00' 'Basepack6' 1
'2014-01-01 13:00:00' 'BaseValuepack' 1
How do I use the rank function to achieve this result?
Try this code, Assuming it is mysql as the code posted looks like mysql
SELECT date,
plan_name,
Sum((SELECT Count(1)
FROM mastertable T2
WHERE t2.phno = tt.phno
AND t2.date = Tt.date
AND ( tt.plan_price > t2.plan_price
OR TT.count = 1 ))) CNT
FROM (SELECT *,
(SELECT Count(1)
FROM mastertable Ti
WHERE ti.date = T.date
AND ti.phno = t.phno) AS Count
FROM mastertable T) Tt
GROUP BY date,
plan_name
Here is the SQL Fiddle Demo
;with cte as
(
select *,ROW_NUMBER()over(partition by phno order by plan_price desc)rn
from #MasterTable
)
,
cte1 as
(
select a.Plan_name,count(*)[Phone_no_count] from cte a
where rn=1
group by a.Plan_name
)
select distinct a.dates,a.Plan_name,isnull(b.Phone_no_count,0)[[Phone_no_count]
from #MasterTable a left join cte1 b on a.Plan_name=b.Plan_name
Related
I'm trying to write query on two different selects with different WHERE clause and using GROUP BY.
I browsed for examples but mine is different since I have multiple fields for SELECT.
Here is example data:
-- drop table #temp_counts;
create table #temp_counts(
report_date smalldatetime not null,
Emp_id varchar(10) not null,
source_system varchar(10) not null
)
Insert into #temp_counts values ('2021-05-02 00:00:00', '12411', 'ABC');
Insert into #temp_counts values ('2021-05-02 00:00:00', '56421', 'ABC');
Insert into #temp_counts values ('2021-05-02 00:00:00', '45411', 'ABC');
Insert into #temp_counts values ('2021-05-02 00:00:00', '75411', 'ABC');
Insert into #temp_counts values ('2021-05-02 00:00:00', '13245', 'XYZ');
Insert into #temp_counts values ('2021-05-02 00:00:00', '66245', 'XYZ');
Insert into #temp_counts values ('2021-05-02 00:00:00', '77245', 'XYZ');
Insert into #temp_counts values ('2021-05-02 00:00:00', '98245', 'XYZ');
Insert into #temp_counts values ('2021-05-02 00:00:00', '34245', 'XYZ');
Insert into #temp_counts values ('2021-05-02 00:00:00', '29245', 'XYZ');
Insert into #temp_counts values ('2021-05-03 00:00:00', '14524', 'ABC');
Insert into #temp_counts values ('2021-05-03 00:00:00', '17824', 'ABC');
Insert into #temp_counts values ('2021-05-03 00:00:00', '32524', 'ABC');
Insert into #temp_counts values ('2021-05-03 00:00:00', '16724', 'XYZ');
Insert into #temp_counts values ('2021-05-03 00:00:00', '19924', 'XYZ');
Insert into #temp_counts values ('2021-05-03 00:00:00', '89424', 'XYZ');
Insert into #temp_counts values ('2021-05-03 00:00:00', '48324', 'XYZ');
Insert into #temp_counts values ('2021-05-03 00:00:00', '16000', 'XYZ');
Insert into #temp_counts values ('2021-05-04 00:00:00', '18724', 'ABC');
Insert into #temp_counts values ('2021-05-04 00:00:00', '12904', 'XYZ');
Insert into #temp_counts values ('2021-05-05 00:00:00', '12074', 'ABC');
Insert into #temp_counts values ('2021-05-05 00:00:00', '12784', 'XYZ');
Insert into #temp_counts values ('2021-05-05 00:00:00', '12324', 'XYZ');
Insert into #temp_counts values ('2021-05-05 00:00:00', '75124', 'XYZ');
These are the queries I would like to merge:
select count(*) emp_count, report_date , 'ABC' source_system from #temp_counts
where source_system = 'ABC'
group by report_date
order by report_date
select count(*) emp_count, report_date , 'XYZ' source_system from #temp_counts
where source_system = 'XYZ'
group by report_date
order by report_date
I tried 2 methods as under:
--Method 1
select fir.emp_count, fir.report_date, fir.source_system from
(select count(*) emp_count, report_date , 'ABC' source_system from #temp_counts
where source_system = 'ABC') as fir
inner join
(select count(*) emp_count, report_date , 'XYZ' source_system from #temp_counts
where source_system = 'XYZ') as sec
on fir.report_date = sec.report_date
group by fir.report_date
order by fir.report_date
--Method 2
select count(*) emp_count, report_date , 'ABC' source_system from #temp_counts
where source_system = 'ABC'
UNION ALL
select count(*) emp_count, report_date , 'XYZ' source_system from #temp_counts
where source_system = 'XYZ'
group by report_date
order by report_date
Both give Error:
Msg 8120, Level 16, State 1, Line 61
Column '#temp_counts.report_date' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Please guide
seems like you just want to group by report_date and source_system:
select count(*) emp_count, report_date , source_system
FROM #temp_counts
group by report_date, source_system
order by source_system,report_date
if you want to have result for specific source systems then you can combine conditions:
select count(*) emp_count, report_date , source_system
FROM #temp_counts
where source_system in ('ABC', 'XYZ')
group by report_date, source_system
order by source_system,report_date
you can change order by to show rows in the order you want to show
just to illustrate how to use union :
select count(*) emp_count, report_date , source_system from #temp_counts
where source_system = 'ABC'
group by report_date
union all
select count(*) emp_count, report_date , source_system from #temp_counts
where source_system = 'XYZ'
group by report_date
order by source_system, report_date
I have a T-SQL table where I have many transition statuses. For every transition pair (AVA_FROM -> AVA_TO) there is a timestamp and I should calculate every duration from status to status. I can't figure how to write a SQL script for my needs.
I wrote here below the sentence for the table creation in SQL Fiddle. Every record with a value in AVA_TO = R-PC is a work start, whilst every record with a value in AVA_FROM = R-PC is a work stop. All the record with the same AVA_PRIMARYID belong to the same work order so they need to be summed. Can you help me to solve such problem?
CREATE TABLE R5AUDVALUES
(
AVA_PRIMARYID nvarchar(8),
AVA_FROM nvarchar(8),
AVA_TO nvarchar(8),
AVA_CHANGED datetime,
AVA_UPDATED nvarchar(1)
);
INSERT INTO R5AUDVALUES (AVA_PRIMARYID, AVA_FROM, AVA_TO, AVA_CHANGED, AVA_UPDATED)
VALUES ('44730', 'Q', 'R-PC', '2020-12-14 12:00:00', '+'),
('44730', 'R-PC', 'SSP4', '2020-12-14 12:15:00', '+'),
('44730', 'SSP4', 'R-PC', '2020-12-14 12:30:00', '+'),
('44730', 'R-PC', 'SSP5', '2020-12-14 12:45:00', '+'),
('44730', 'SSP5', 'R-PC', '2020-12-14 13:00:00', '+'),
('44730', 'R-PC', 'C', '2020-12-14 13:15:00', '+')
The result should be like the following :
WorkOrder, WorkStart, WorkStop
'44730', 2020-12-14 12:00:00', '2020-12-14 12:15:00',
'44730', 2020-12-14 12:30:00', '2020-12-14 12:45:00',
'44730', 2020-12-14 13:00:00', '2020-12-14 13:15:00'
If the dataset is regular then just row_number() and join.
with c as (
select AVA_PRIMARYID, AVA_FROM, AVA_TO, AVA_CHANGED, AVA_UPDATED, row_number()over (order by AVA_CHANGED) n
from R5AUDVALUES
)
select a.*, b.AVA_CHANGED, datediff(minute, a.AVA_CHANGED, b.AVA_CHANGED) minutes
from c a
join c b on a.n+1 = b.n and a.AVA_TO = 'R-PC' and b.AVA_FROM = 'R-PC'
Otherwise you may need a data cleaning step first.
db<>Fiddle
I want to see how long the client spend time connecting to our website daily.
My table source in created as below and contains the data as shown below.
CREATE TABLE source_ (
"nbr" numeric (10),
"begdate" timestamp,
"enddate" timestamp,
"str" varchar(35))
;
INSERT INTO source_
("nbr", "begdate", "enddate", "str")
VALUES
(111, '2019-11-25 07:00:00', '2019-11-25 08:00:00', 'TMP123'),
(222, '2019-03-01 12:04:02', '2019-03-01 12:05:02', 'SOC'),
(111, '2019-11-25 19:00:00', '2019-11-25 19:30:00', 'TMP12'),
(444, '2020-02-11 22:00:00', '2020-02-12 02:00:00', 'MARATEN'),
(444, '2020-02-11 23:00:00', '2020-02-12 01:00:00', 'MARA12'),
(444, '2020-02-12 13:00:00', '2020-02-12 14:00:00', 'MARA12'),
(444, '2020-02-12 07:00:00', '2020-02-12 08:00:00', 'MARA1222')
;
create table target_ (nbr numeric (10), date_ int(10), state varchar(30), terms interval);
I did an attempt below, but as you can see i associated the date_ (day of the event) to the beddate which is not always true see (4th row) when the event is between two days.
INSERT INTO target_
(nbr, date_, state, terms)
select
nbr,
DATE_TRUNC('day', begdate) as date_,
state,
sum(term) as terms
from (
select
nbr, begdate,
(case
when trim(str) ~ '^TMP' then 'TMP'
when trim(str) ~ '^MARA' then 'MARATEN'
else 'SOC'
end) as state,
(enddate - begdate)as term from source_ ) X
group by nbr, date_, state;
expected output
111 2019-11-25 00:00:00+00 TMP 90
222 2019-03-01 00:00:00+00 SOC 60
444 2020-02-11 00:00:00+00 MARATEN 180
444 2020-02-12 00:00:00+00 MARATEN 300
If I understand correctly, you can use generate_series() to expand the periods and then aggregate:
select gs.dte,
(case when trim(str) ~ '^TMP' then 'TMP'
when trim(str) ~ '^MARA' then 'MARATEN'
else 'SOC'
end) as state,
sum( least(s.enddate, gs.dte + interval '1 day') - greatest(s.begdate, gs.dte))
from source s cross join lateral
generate_series(begdate::date, enddate::date, interval '1 day') gs(dte)
group by state, gs.dte
order by gs.dte, state;
Here is a db<>fiddle.
I want to get the previous record of each record in Table A from Table B.
for easy, below is the table sample data:
drop table if exists #A
drop table if exists #B
CREATE TABLE #A(Name varchar(10), time datetime, value int)
insert into #A values
('A', '2020-03-31 18:00:00', 56),
('A', '2020-03-31 19:00:00', 3),
('B', '2020-03-31 14:00:00', 14),
('C', '2020-03-31 15:00:00', 26)
CREATE TABLE #B(Name varchar(10), time datetime, value int)
insert into #A values
('A', '2020-03-31 21:00:00', 79),
('A', '2020-03-31 17:00:00', 44),
('A', '2020-03-31 14:00:00', 76),
('B', '2020-03-31 18:00:00', 89),
('C', '2020-03-31 11:00:00', 29),
('C', '2020-03-31 08:00:00', 6)
EDIT:
It should include only last previous record from TableB.
Sorry for the confusion. Changed image and sample data also.
I think you want:
select a.name, a.time, a.value
from #a a
union all
select b.name, b.time, b.value
from (select b.*, row_number() over (order by time desc) as seqnum
from #b b
where b.time < (select min(a.time)
from #a a
where a.name = b.name
)
) b
where seqnum = 1
order by name, time;
Here is a db<>fiddle.
EDIT:
If b could have multiple "previous" records, then:
select a.name, a.time, a.value
from #a a
union all
select b.name, b.time, b.value
from (select b.*,
row_number() over (partition by b.name order by b.time desc) as seqnum
from #b b
where b.time < (select min(a.time)
from #a a
where a.name = b.name
)
) b
where seqnum = 1
order by name, time;
Here is a db<>fiddle for this version.
I have a snapshot table which has a daily level information for a particular product and its price.
all I want to achieve is compare the state of this product from its current state to its previous state 2 months back.
Here is the ddl
CREATE TABLE Prod_snapshot
('Base_Date' datetime, 'Product_code' varchar(4));
INSERT INTO Prod_snapshot
('Base_Date', 'Product_code')
VALUES
('2013-10-01 13:00:00', 'VD1'),
('2013-10-01 13:00:00', 'VD2'),
('2013-10-01 13:00:00', 'VD2'),
('2013-10-01 13:00:00', 'VD1'),
('2013-10-01 13:00:00', 'VD3'),
('2013-10-01 13:00:00', 'VD9'),
('2014-02-01 13:00:00', 'VD1'),
('2014-02-01 13:00:00', 'VD2'),
('2014-02-01 13:00:00', 'VD10');
Here is the sql fiddle.
Here is my desired Output
Base_date Product_Code Active_on_01_oct_2013
01/02/2014 VD1 'Y'
01/02/2014 VD2 'Y'
01/02/2014 VD10 'N'
The basics of the query would be something like:
DECLARE #DateOfInterest date
SET #DateOfInterest = '20140201'
SELECT p1.Base_Date,pr.Product_Code,
CASE WHEN p2.Product_Code IS NULL THEN 'N' ELSE 'Y' END as PreviouslyActive
FROM
Prod_snapshot p1
left join
Prod_snapshot p2
on
p1.Product_Code = p2.Product_Code and
p2.Base_Date = DATEADD(month,-4 /* narrative says 2 */,#DateOfInterest)
WHERE
p1.Base_Date = #DateOfInterest