I have the following table, tblCPDates
cDate date
cp nvarchar(10)
Example of the data
cDate cp
2016-01-01 AB
2016-01-01 MN
2016-02-01 EF
2016-03-01 AB
2016-04-01 MN
What I would like
cDate AB MN EF
2016-01-01 1 1 0
2016-02-01 0 0 1
2016-03-01 1 0 0
2016-04-01 0 1 0
Is this possible?
I tried the following but obviously only return the last date
select * from
(
select distinct cDate, cp from tblCPDDates
)source pivot(max(cDate) for cp in ([AB], [MN], [EF])) as pvt
You could do this with an aggregated CASE;
Sample Data
CREATE TABLE #tblCPDates (cDate date, cp nvarchar(10))
INSERT INTO #tblCPDates (cDate, cp)
VALUES
('2016-01-01','AB')
,('2016-01-01','MN')
,('2016-02-01','EF')
,('2016-03-01','AB')
,('2016-04-01','MN')
Query
SELECT
cDate
,SUM(CASE WHEN cp = 'AB' THEN 1 ELSE 0 END) AB
,SUM(CASE WHEN cp = 'MN' THEN 1 ELSE 0 END) MN
,SUM(CASE WHEN cp = 'EF' THEN 1 ELSE 0 END) EF
FROM #tblCPDates
GROUP BY cDate
Output
cDate AB MN EF
2016-01-01 1 1 0
2016-02-01 0 0 1
2016-03-01 1 0 0
2016-04-01 0 1 0
try this out : by using pivot it is more easier :
CREATE TABLE #tblCPDates (cDate date, cp nvarchar(10))
INSERT INTO #tblCPDates (cDate, cp)
VALUES
('2016-01-01','AB')
,('2016-01-01','MN')
,('2016-02-01','EF')
,('2016-03-01','AB')
,('2016-04-01','MN')
select *
from
(
select cDate, cp
from #tblCPDates
) src
pivot
(
Count(cp)
for cp in ([AB], [MN],[EF])
) piv;
TryThis.
select
cDate ,
case when ab='AB' then 1 else 0 end as AB,
case when MN='MN' then 1 else 0 end as MN,
case when EF='EF' then 1 else 0 end as EF
from
(
select distinct cDate, cp from tblCPDates
)source pivot(max(cp) for cp in ([AB], [MN], [EF])) as pvt
Using pivot for get result :
`CREATE TABLE #table(Id INT,cDate DATE,cp VARCHAR(10))
INSERT INTO #table(Id,cDate ,cp )
SELECT 1,'2016-01-01','AB' UNION ALL
SELECT 1,'2016-01-01','MN' UNION ALL
SELECT 1,'2016-02-01','EF' UNION ALL
SELECT 1,'2016-03-01','AB' UNION ALL
SELECT 1,'2016-04-01','MN'
SELECT cDate,ISNULL([AB],0) [AB],ISNULL([MN],0) [MN],ISNULL([EF],0) [EF]
FROM
( SELECT Id,cDate ,cp FROM #table ) A PIVOT (MAX(Id) FOR cp IN ([AB],[MN],[EF])) pvt`
Related
I have this below table
App No EventCode Event Date
---------------------------------------------------------
1 A 2010-01-01
1 B 2010-01-02
1 C 2010-01-03
1 A 2010-01-10
2 A 2010-01-04
2 C 2010-01-05
2 B 2010-01-06
3 A 2010-01-01
3 D 2010-01-11
4 A 2011-01-01
4 D 2011-01-02
4 C 2011-03-03
I need to find out whether the App No has atleast an event A followed by Event C without having Event B in between. Please advise if this can be done using group by App No. I already have a complex query that groups by app no for calculating various values. I need to integrate this one to that.
The result table should look like
[App No] [A Immediately Followed By C] [Max A date]
-------------------------------------------------------
1 0 2010-01-10
2 1 2010-01-04
3 0 2010-01-01
4 1 2011-01-01
You should use lead() for this with aggregation and filtering:
select appno,
(case when max(case when eventcode = 'A' and next_ec = 'C' then 1 else 0 end) > 0
then 1 else 0
end) as flag,
max(case when eventcode = 'A' then date end) as max_a_date
from (select t.*,
lead(eventcode) over (partition by appno order by date) as next_ec
from t
where eventcode <> 'B'
) t
group by appno;
EDIT:
In SQL Server 2008, you can do:
select appno,
(case when max(case when eventcode = 'A' and next_ec = 'C' then 1 else 0 end) > 0
then 1 else 0
end) as flag,
max(case when eventcode = 'A' then date end) as max_a_date
from (select t.*,
t2.eventcode as next_ec
from t outer apply
(select top (1) t2.*
from t t2
where t2.appno = t.appno and t2.date > t.date
order by t2.date desc
) tnext
where eventcode <> 'B'
) t
group by appno;
I can't remember a way to solve this with aggregating, but you can use LEAD() (which you can use in SQL SERVER 2012+) or ROW_NUMBER() for SQL Server 2008+.
So here is sample data and temporary table.
...after reading through comments added on question, updated version:
CREATE TABLE #table_name (
app_no int,
event_code char(1),
event_date date
);
insert into #table_name
values
(1,'A',GETDATE()-100),
(1,'B',GETDATE()-10),
(1,'C',GETDATE()-1),
(2,'A',GETDATE()+10),
(2,'A',GETDATE()+1),
(2,'D',GETDATE()),
(2,'C',GETDATE()+10),
(3,'A',GETDATE()),
(3,'C',GETDATE()+100)
select *
,ROW_NUMBER() over (partition by 1 order by app_no) as rowid
into #table_name2
from #table_name
where event_code in ('A','B','C')
select org.app_no
,org.event_code
,case
when rez2.event_code is not null then 1
else 0
end as 'A followed by C'
,case
when rez2.max_date is not null then rez2.max_date
else org.event_date
end as 'Max A date'
from #table_name2 org
left outer join (
select t1.*,d.max_date
from #table_name2 t1
inner join #table_name2 t2 on t2.rowid=t1.rowid+1
left outer join
(
select app_no,event_code,MAX(event_date) as max_date
from #table_name
group by app_no,event_code
)d on d.app_no=t1.app_no and d.event_code=t1.event_code
where t1.event_code='A' and t2.event_code='C'
)rez2 on rez2.app_no=org.app_no and rez2.event_code=org.event_code and rez2.event_date=org.event_date
where org.event_code='A'
drop table #table_name
drop table #table_name2
;WITH cte
AS
(
SELECT tn.app_no
,tn.event_code
,tn.event_date
,LEAD(tn.event_code) OVER (PARTITION BY tn.app_no ORDER BY tn.event_date) NextEvent
FROM <Your_Table> AS tn
)
SELECT app_no
,MAX(CASE WHEN cte.NextEvent='C'
THEN 1
ELSE 0
END) AS [A Immediately Followed By C]
,MAX(event_date) event_date
FROM cte
WHERE event_code='A'
GROUP BY app_no
I try this query
Select
S.Name,S.No,
SUM(Case when s.Model='Cultus' then total else 0 end) as Cultus,
SUM(Case when s.Model ='vigo' then total else 0 end) as vigo,
SUM(total) total_v ,
s.MA,MAX(S.Speed) Speed
from (
Select
RVU.Name,RVU.No,VV.Model,count(VV.Model) as total, RVU.MA as MA,RVU.Speed
from
VV
inner join RVU
on VV.MID=RVU.ID
inner join RU on RVU.RID= RU.RID
WHERE
RU.StartDate>= '2016-04-01 00:00:00' and
RU.EndDate<='2016-04-30 23:59:59' and
RU.Region= 'Paris'
and RVU.No= '651' AND Model <> ''
Group By RVU.Name,RVU.RegNo,VV.Model,RVU.MA,RVU.Speed ) S
GROUP BY
s.RegNo,s.Name,S.MA
Ouput
Name No Cultus vigo total_v MA Speed
David 651 2 0 2 1048 124
David 651 3 0 3 597 345
David 651 1 0 1 606 101
David 651 3 2 5 992 110
when i try this
Sum(MA) MA,
THIS SHOW ERROR
Operand data type varchar is invalid for sum operator.
I want result like this
Name No Cultus vigo total_v MA Speed
David 651 9 2 11 1799 345
UPDATE
when i try this
SUM(CASE ISNULL(MA,'') WHEN '' THEN 0 ELSE CAST(MA AS INT) END),
and also this
sum(cast (MA as int))
then output is
Name No Cultus vigo total_v MA Speed
David 651 2 0 2 4192 124
David 651 3 0 3 2388 345
David 651 1 0 1 2424 101
David 651 3 2 5 4960 110
updated 2:
when i execute only this part this show multiple records with same data
Select
RVU.Name,RVU.No,VV.Model,count(VV.Model) as total, RVU.MA as MA,RVU.Speed
from
VV
inner join RVU
on VV.MID=RVU.ID
inner join RU on RVU.RID= RU.RID
WHERE
RU.StartDate>= '2016-04-01 00:00:00' and
RU.EndDate<='2016-04-30 23:59:59' and
RU.Region= 'Paris'
and RVU.No= '651' AND Model <> ''
Group By RVU.Name,RVU.RegNo,VV.Model,RVU.MA,RVU.Speed
looks like value totally change
There may be a chance of string value in the column RVU.MA. Try out with the below query to find out such descrepancies.
SELECT *
FROM RVU
WHERE ISNUMERIC (RVU.MA)!=1
You can use below syntax to get your answer.
select sum(cast(columnname as int)) from TableName
Try applying this syntax:
select sum(cast(s.MA as int)) from (
Select
RVU.Name,RVU.No,VV.Model,count(VV.Model) as total, RVU.MA as MA,RVU.Speed
from
VV
inner join RVU
on VV.MID=RVU.ID
inner join RU on RVU.RID= RU.RID
WHERE
RU.StartDate>= '2016-04-01 00:00:00' and
RU.EndDate<='2016-04-30 23:59:59' and
RU.Region= 'Paris'
and RVU.No= '651' AND Model <> ''
Group By RVU.Name,RVU.RegNo,VV.Model,RVU.MA,RVU.Speed ) S
Check this query, whether you were able to select your record and apply this logic in your query.
Your final query looks like,
Select
S.Name,S.No,
SUM(Case when s.Model='Cultus' then total else 0 end) as Cultus,
SUM(Case when s.Model ='vigo' then total else 0 end) as vigo,
SUM(total) total_v ,
sum(cast(s.MA as int)),MAX(S.Speed) Speed
from (
Select
RVU.Name,RVU.No,VV.Model,count(VV.Model) as total, RVU.MA as MA,RVU.Speed
from
VV
inner join RVU
on VV.MID=RVU.ID
inner join RU on RVU.RID= RU.RID
WHERE
RU.StartDate>= '2016-04-01 00:00:00' and
RU.EndDate<='2016-04-30 23:59:59' and
RU.Region= 'Paris'
and RVU.No= '651' AND Model <> ''
Group By RVU.Name, RVU.RegNo, VV.Model, RVU.MA, RVU.Speed ) S
GROUP BY
s.RegNo, s.Name, S.MA
create table #t
(
id varchar(20))
insert into #t
select '2'
union all
select '3'
select sum(id) from #t--this fails
You need to do
select sum(cast (id as int))--cast from 2008 onwards
from #t
In your case MA column is of type Varchar
Seems that one of your MA column value is type of varchar, please check your data
If your data type varchar then cast to INT:
SUM(CASE ISNULL(MA,'') WHEN '' THEN 0 ELSE CAST(MA AS INT) END)
DECLARE #tblTest as Table(
Name VARCHAR(10),
No INT,
Cultus INT,
vigo INT,
total_v INt,
MA VARCHAR(5),
Speed INT
)
INSERT INTO #tblTest VALUES
('David',651,2,0,2,1048,124)
,('David',651,3,0,3,597,345)
,('David',651,1,0,1,606,101)
,('David',651,3,2,5,992,110)
SELECT
Name,[No],SUM(Cultus),
SUM(vigo) AS vigo ,SUM(total_v) AS total_v,
SUM(CASE ISNULL(MA,'') WHEN '' THEN 0 ELSE CAST(MA AS INT) END) AS MA,
MAX(Speed) AS Speed
FROM #tblTest
GROUP BY Name,[No]
I need to show serial numbers for each row of an invoice. That means, that on one position there can be several serial numbers. Along with the serial number there needs to be a quantity, which is obviously allways one. Unfortunately, there could be rows with more items than serial numbers. This happens when serial numbers are not scanned in the shipping process. In my output I need an extra row for these positions where I show the number of REMAINING items. So let's say, that there is a position with 10 items in it and only four are scanned in the shipping process. That would mean I print four rows with the serials and quantity one and a fith row with no serial and the quantity six.
I work with SQL Server 2008 and would prefer a solution without temp tables or CTEs.
Here is an example of what I mean:
CREATE TABLE #data (doc int, pos int, qty int)
CREATE TABLE #serial (doc int, pos int, serial varchar(10))
INSERT INTO #data
SELECT 1,1,6
UNION ALL
SELECT 1,2,3
UNION ALL
SELECT 2,1,4
INSERT INTO #serial
select 1,1,'aaaaaaaaaa'
UNION ALL
select 1,1,'bbbbbbbbbb'
UNION ALL
select 1,1,'cccccccccc'
UNION ALL
select 1,1,'dddddddddd'
UNION ALL
select 1,2,'eeeeeeeeee'
UNION ALL
select 1,2,'ffffffffff'
UNION ALL
select 1,2,'gggggggggg'
UNION ALL
select 2,1,'hhhhhhhhhh'
SELECT d.doc, d.pos, s.serial, CASE WHEN s.serial IS NOT NULL THEN 1 ELSE d.qty END qty
FROM #data d
INNER JOIN #serial s ON s.doc = d.doc and s.pos = d.pos
This is the desired output:
doc | pos | serial | qty
1 | 1 |'aaaaaaaaaa'| 1
1 | 1 |'bbbbbbbbbb'| 1
1 | 1 |'cccccccccc'| 1
1 | 1 |'dddddddddd'| 1
1 | 1 | NULL | 2
1 | 2 |'eeeeeeeeee'| 1
1 | 2 |'ffffffffff'| 1
1 | 2 |'gggggggggg'| 1
2 | 1 |'hhhhhhhhhh'| 1
2 | 1 | NULL | 3
select
s.doc, s.pos, s.serial, d.qty - s.cnt qty
from
( select
s.doc, s.pos, s.serial, count(*) cnt,
case when grouping(s.doc) = 0 and grouping(s.pos) = 0 and grouping(s.serial) = 1 then 1 else 0 end grp
from
#serial s
group by
s.doc, s.pos, s.serial with cube
having
grouping(s.doc) = 0 and grouping(s.pos) = 0 and grouping(s.serial) = 1
or grouping(s.doc) = 0 and grouping(s.pos) = 0 and grouping(s.serial) = 0
) s
left join #data d on s.doc = d.doc and s.pos = d.pos and s.grp = 1
where
s.grp = 0 or d.qty - s.cnt > 0
order by
s.doc, s.pos, s.grp
Dynamic approach
SELECT d.doc, d.pos, s.serial, 1 qty
FROM #data d
INNER JOIN #serial s ON s.doc = d.doc and s.pos = d.pos
UNION
select t1.doc,t1.pos,null,t1.qty-ss from
(
SELECT d.doc,d.pos, SUM(1) SS , d.qty
FROM #data d
INNER JOIN #serial s ON s.doc = d.doc and s.pos = d.pos
group by d.doc,d.pos,d.qty
)t1 where SS<>qty
Order by d.doc,d.pos,s.serial
Are you looking for this ..?
SELECT d.doc, d.pos, s.serial, CASE WHEN s.serial IS NOT NULL THEN 1 ELSE d.qty END qty
FROM #data d
INNER JOIN #serial s ON s.doc = d.doc AND s.pos = d.pos
UNION ALL
SELECT d.doc, d.pos, NULL serial, d.qty - s.qty
FROM #data d
INNER JOIN (
SELECT doc, pos, count(*) AS qty
FROM #serial
GROUP BY doc, pos
) s ON s.doc = d.doc AND s.pos = d.pos
WHERE d.qty - s.qty <> 0
ORDER BY doc, pos
Output
doc pos serial qty
1 1 aaaaaaaaaa 1
1 1 bbbbbbbbbb 1
1 1 cccccccccc 1
1 1 dddddddddd 1
1 1 NULL 2
1 2 eeeeeeeeee 1
1 2 ffffffffff 1
1 2 gggggggggg 1
2 1 hhhhhhhhhh 1
2 1 NULL 3
I'm working on the following query and table
SELECT dd.actual_date, dd.week_number_overall, sf.branch_id, AVG(sf.overtarget_qnt) AS targetreach
FROM sales_fact sf, date_dim dd
WHERE dd.date_id = sf.date_id
AND dd.week_number_overall BETWEEN 88-2 AND 88
AND sf.branch_id = 1
GROUP BY dd.actual_date, branch_id, dd.week_number_overall
ORDER BY dd.actual_date ASC;
ACTUAL_DATE WEEK_NUMBER_OVERALL BRANCH_ID TARGETREACH
----------- ------------------- ---------- -----------
13/08/14 86 1 -11
14/08/14 86 1 12
15/08/14 86 1 11.8
16/08/14 86 1 1.4
17/08/14 86 1 -0.2
19/08/14 86 1 7.2
20/08/14 87 1 16.6
21/08/14 87 1 -1.4
22/08/14 87 1 14.4
23/08/14 87 1 2.8
24/08/14 87 1 18
26/08/14 87 1 13.4
27/08/14 88 1 -1.8
28/08/14 88 1 10.6
29/08/14 88 1 7.2
30/08/14 88 1 14
31/08/14 88 1 9.6
02/09/14 88 1 -3.2
the "TargetReach" column shows whether target has been reach or not.
A negative value means target wasn't reached on that day.
How can I get calculate the number of ROW with positive value for this query?
that will show something like:
TOTAL_POSITIVE_TARGET_REACH WEEK_NUMBER_OVERALL
--------------------------- ------------------
13 88
I have tried to use CASE but still not working right.
Thanks a lot.
You want to use conditional aggregation:
with t as (
<your query here>
)
select week_number_overall, sum(case when targetreach > 0 then 1 else 0 end)
from t
group by week_number_overall;
However, I would rewrite your original query to use proper join syntax. Then the query would look like:
SELECT week_number_overall,
SUM(CASE WHEN targetreach > 0 THEN 1 ELSE 0 END)
FROM (SELECT dd.actual_date, dd.week_number_overall, sf.branch_id, AVG(sf.overtarget_qnt) AS targetreach
FROM sales_fact sf JOIN
date_dim dd
ON dd.date_id = sf.date_id
WHERE dd.week_number_overall BETWEEN 88-2 AND 88 AND sf.branch_id = 1
GROUP BY dd.actual_date, branch_id, dd.week_number_overall
) t
GROUP BY week_number_overall
ORDER BY week_number_overall;
THe difference between a CTE (the first solution) and a subquery is (in this case) just a matter of preference.
SELECT WEEK_NUMBER_OVERALL, COUNT(*) TOTAL_POSITIVE_TARGET_REACH
FROM (your original query)
WHERE TARGETREACH >= 0
GROUP BY WEEK_NUMBER_OVERALL
select sum( decode( sign( TARGETREACH ) , -1 , 0 , 0 , 0 , 1 , 1 ) )
from ( "your query here" );
Use HAVING Clause
SELECT dd.actual_date, dd.week_number_overall, sf.branch_id, AVG(sf.overtarget_qnt) AS targetreach
FROM sales_fact sf, date_dim dd
WHERE dd.date_id = sf.date_id
AND dd.week_number_overall BETWEEN 88-2 AND 88
AND sf.branch_id = 1
GROUP BY dd.actual_date, branch_id, dd.week_number_overall
HAVING AVG(sf.overtarget_qnt)>0
ORDER BY dd.actual_date ASC;
Using decode(), sign() get both positive count & negative count.
drop table test;
create table test (
key number(5),
value number(5));
insert into test values ( 1, -9 );
insert into test values ( 2, -8 );
insert into test values ( 3, 10 );
insert into test values ( 4, 12 );
insert into test values ( 5, -9 );
insert into test values ( 6, 8 );
insert into test values ( 7, 51 );
commit;
select sig , count ( sig ) from
(
select key, ( (decode( sign( value ) , -1 , '-ve' , 0 , 'zero' , 1 , '+ve' ) ) ) sig
from test
)
group by sig
SIG COUNT(SIG)
---- ----------------------
+ve 4
-ve 3
I have a history of records (multiple records per update all with the exact same datetime) that share an IdString.
I want a query to determine which of these records are part of the most recent update group.
This query will show me one of the records having the most recent update date, but for each partition, I need all the records with that max date.
;with cte as(
select ROW_NUMBER() over (partition by IdString order by UpdateDate desc) as [rn], *
from MyTable
)
select CASE WHEN (cte.rn = 1) THEN 0 ELSE 1 END [IsOld], *
from MyTable m
inner join cte on cte.RecordId= m.RecordId
Would someone please help me figure out an appropriate query?
EDIT: Sample
(IsOld is the desired calculated value)
IsOld RecordId IdString UpdateDate
1 1 ABC 2011-06-16
1 2 ABC 2012-05-30
1 3 ABC 2008-12-31
0 4 ABC 2012-06-08
1 5 ABC 2011-01-16
0 6 ABC 2012-06-08
1 7 ABC 2012-06-07
1 8 XYZ 2001-01-16
1 9 XYZ 2013-01-30
0 10 XYZ 2001-01-31
1 11 XYZ 2013-06-01
1 12 XYZ 2001-05-04
0 13 XYZ 2013-01-30
SELECT CASE WHEN updateDate = maxDate THEN 0 ELSE 1 END isOldRecord, RecordID, IDString, UpdateDate
FROM
(
select m.RecordID, m.IDString, m.updateDate, MAX(UpdateDate) OVER (PARTITION BY IDString) maxDate
from MyTable m
) A
Try this -
;WITH cte AS(
SELECT RANK() OVER(PARTITION BY IdString ORDER BY UpdateDate DESC) AS [row_num], *
FROM MyTable
)
SELECT CASE WHEN m.[row_num] = 1 THEN 0 ELSE 1 END isOld, *
from cte m