How to use update statement when there is a conditional aggregation?
because i need to update this query to my table REPORTDATA.
my column in table REPORTDATA is DEPARTMENT,MONTHS,YEARS,RTOTALLOSTTIME,RLATECOME,REARLYLEAVE,RST,ROT as i mentioned in this select query :
is it possible to use update statement in this query?
select s.department
,s.month
,s.year
,count(case when s.sum_lost_time >='02:00:00' then NAME end) as RTOTALLOSTTIME
,count(case when s.sum_late >='00:00:01' then NAME end) as RLATECOME
,count(case when s.sum_early >='00:00:01' then NAME end) as REARLYLEAVE
,count(case when s.sum_st <='8' then NAME end) as RST
,count(case when s.sum_ot >='1' then NAME end) as ROT
from (select MONTH(STATUSIN) as [month]
,YEAR(STATUSIN) as [year]
,NIP
,NAME
,DEPARTMENT
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(TOTALLT as time))),0),108) as sum_lost_time
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(LATECOME as time))),0),108) as sum_late
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(EARLYLEAVE as time))),0),108) as sum_early
,SUM(CAST(STRAIGHTTIME AS FLOAT)) as sum_st
,SUM(CAST(OT AS FLOAT)) as sum_ot
from SUMMARYDATA b
group by MONTH(STATUSIN)
,YEAR(STATUSIN)
,NIP
,NAME
,DEPARTMENT
)s
group by s.department
,s.month
,s.year
this is what i've tried so far,but appear error 'An aggregate may not appear in the set list of an UPDATE statement' and can't use group by too
merge
into REPORTDATA r
using (select MONTH(STATUSIN) as [month]
,YEAR(STATUSIN) as [year],NIP
,NAME
,DEPARTMENT
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(TOTALLT as time))),0),108) as sum_lost_time
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(LATECOME as time))),0),108) as sum_late
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(EARLYLEAVE as time))),0),108) as sum_early
from SUMMARYDATA b
group by MONTH(STATUSIN)
,YEAR(STATUSIN)
,NIP
,NAME
,DEPARTMENT
)s
on r.department=s.department
when matched then
update
set DEPARTMENT = s.DEPARTMENT,
RLOSTTIME = count(case when s.sum_lost_time >='02:00:00' then NAME end),
RLATECOME = count(case when s.sum_late >='00:00:01' then NAME end),
REARLYLEAVE = count(case when s.sum_early >='00:00:01' then NAME end);
group by s.department
,s.month
,s.year
You seem to want:
with q as (
<your query here>
)
update rd
set rtotallosttime = q.rtotallosttime,
. . . -- rest of columns
from reportdata rd join
q
on rd.department = q.department and
rd.month = q.month and
rd.year = q.year;
That said, I'm surprised you would approach this with update. I would think you would want to insert the rows instead.
Use MERGE:
merge
into REPORTDATA r
using ( select s.department as department
,s.month as month
,s.year as year
,count(case when s.sum_lost_time >='02:00:00' then NAME end) as RTOTALLOSTTIME
,count(case when s.sum_late >='00:00:01' then NAME end) as RLATECOME
,count(case when s.sum_early >='00:00:01' then NAME end) as REARLYLEAVE
,count(case when s.sum_st <='8' then NAME end) as RST
,count(case when s.sum_ot >='1' then NAME end) as ROT
from (select MONTH(STATUSIN) as [month]
,YEAR(STATUSIN) as [year]
,NIP
,NAME
,DEPARTMENT
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(TOTALLT as time))),0),108) as sum_lost_time
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(LATECOME as time))),0),108) as sum_late
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(EARLYLEAVE as time))),0),108) as sum_early
,SUM(CAST(STRAIGHTTIME AS FLOAT)) as sum_st
,SUM(CAST(OT AS FLOAT)) as sum_ot
from SUMMARYDATA b
group by MONTH(STATUSIN)
,YEAR(STATUSIN)
,NIP
,NAME
,DEPARTMENT
)s
group by s.department
,s.month
,s.year
)s
on r.department=s.department
when matched then
update
set r.month = s.month,
r.year=s.year,
r.RTOTALLOSTTIME=s.RTOTALLOSTTIME,
r.RLATECOME=s.RLATECOME,
r.REARLYLEAVE=s.REARLYLEAVE,
r.RST=s.RST,
r.ROT=s.ROT
Remember for update there should be common key between REPORTDATA table and Sub query output.
Related
I have 2 queries and I need to combine them into one query with an insert statement.
This is my first query that already has an insert statement:
with q as (
select s.department
,s.months
,s.years
,count(case when s.sum_lost_time >='10:00:00' then NAME end) as RTOTALLOSTTIME
,count(case when s.sum_ot >='20' then NAME end) as ROT
from (select MONTH(STATUSIN) as [months]
,YEAR(STATUSIN) as [years]
,NIP
,NAME
,DEPARTMENT
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(TOTALLT as time))),0),108) as sum_lost_time
,SUM(CAST(OT AS FLOAT)) as sum_ot
from SUMMARYDATA b
group by MONTH(STATUSIN)
,YEAR(STATUSIN)
,NIP
,NAME
,DEPARTMENT
)s
group by s.department
,s.months
,s.years
)
INSERT INTO REPORTDATA(DEPARTMENT,MONTHS,YEARS,RTOTALLOSTTIME,ROT)
SELECT DEPARTMENT,MONTHS,YEARS,RTOTALLOSTTIME,ROT
FROM q
This is the result from first query in table REPORTDATA:
And this is my second query.
WITH cte AS
(
SELECT DISTINCT [NAME], DEPARTMENT, MONTH(STATUSIN) [MONTH], YEAR(STATUSIN) [YEAR],
SUM(CASE WHEN LATECOME = '00:00:00' THEN 0 ELSE 1 END) OVER(PARTITION BY [NAME], DEPARTMENT, MONTH(STATUSIN), YEAR(STATUSIN)) Total
,SUM(CASE WHEN EARLYLEAVE = '00:00:00' THEN 0 ELSE 1 END) OVER(PARTITION BY [NAME], DEPARTMENT, MONTH(STATUSIN), YEAR(STATUSIN)) TotalEarlyLeave
FROM SUMMARYDATA
)
SELECT SUM(CASE WHEN TOTAL > 2 THEN 1 ELSE 0 END) LATECOME,
SUM(CASE WHEN TotalEarlyLeave > 1 THEN 1 ELSE 0 END) EARLYLEAVE
FROM cte
GROUP BY DEPARTMENT, [MONTH], [YEAR]
And this is the result from second query:
I want to place it into my first query but I don't know how to combine it into one in insert statement. Can anyone solve my problems?
This is the sample to my first query: Count summary records per month with conditional SQL
and this is the sample to second query: Count records per month with condition in SQL Server
It's easy if you concatenate your queries as multiple CTEs, and finally JOIN them.
Like this :
;
with cte1 as (
select s.department
,s.months
,s.years
,count(case when s.sum_lost_time >='10:00:00' then NAME end) as RTOTALLOSTTIME
,count(case when s.sum_ot >='20' then NAME end) as ROT
from (select MONTH(STATUSIN) as [months]
,YEAR(STATUSIN) as [years]
,NIP
,NAME
,DEPARTMENT
,convert(varchar,dateadd(second,sum(datediff(second,'00:00:00',cast(TOTALLT as time))),0),108) as sum_lost_time
,SUM(CAST(OT AS FLOAT)) as sum_ot
from SUMMARYDATA b
group by MONTH(STATUSIN)
,YEAR(STATUSIN)
,NIP
,NAME
,DEPARTMENT
)s
group by s.department
,s.months
,s.years
),
cte2 as (
SELECT DISTINCT [NAME], DEPARTMENT, MONTH(STATUSIN) [MONTH], YEAR(STATUSIN) [YEAR],
SUM(CASE WHEN LATECOME = '00:00:00' THEN 0 ELSE 1 END) OVER(PARTITION BY [NAME], DEPARTMENT, MONTH(STATUSIN), YEAR(STATUSIN)) Total
,SUM(CASE WHEN EARLYLEAVE = '00:00:00' THEN 0 ELSE 1 END) OVER(PARTITION BY [NAME], DEPARTMENT, MONTH(STATUSIN), YEAR(STATUSIN)) TotalEarlyLeave
FROM SUMMARYDATA
),
cte3 as (
SELECT DEPARTMENT, [MONTH], [YEAR], SUM(CASE WHEN TOTAL > 2 THEN 1 ELSE 0 END) LATECOME,
SUM(CASE WHEN TotalEarlyLeave > 1 THEN 1 ELSE 0 END) EARLYLEAVE
FROM cte2
GROUP BY DEPARTMENT, [MONTH], [YEAR]
)
INSERT INTO REPORTDATA (DEPARTMENT, MONTHS, YEARS, RTOTALLOSTTIME, ROT, RLATECOME, REARLYLEAVE)
SELECT cte1.DEPARTMENT, cte1.MONTHS, cte1.YEARS, cte1.RTOTALLOSTTIME, cte1.ROT,
cte3.LATECOME, cte3.EARLYLEAVE
FROM cte1
LEFT JOIN cte3 ON cte3.DEPARTMENT = cte1.DEPARTMENT and cte3.[MONTH] = cte1.[MONTH] and cte3.[YEAR] = cte1.[YEAR]
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.
select
compcode, emplcode, attndate, costcode,
decode(shiftflg, 'I', readtime) INTIME,
decode(shiftflg, 'O', readtime) OUTTIME
from
ecatnrec
where
emplcode = 'RF025'
order by
emplcode;
You can use aggregation:
select compcode, emplcode, attndate, costcode,
max(case when shiftflg = 'I' then readtime end) as INTIME,
max(case when shiftflg = 'O' then readtime end) as OUTTIME
from ecatnrec
where emplcode = 'RF025'
group by compcode, emplcode, attndate, costcode
order by emplcode;
This assumes that there is at most on "I" and one "O" row for unique values of the group by keys.
I am writing a query that groups over two columns. this means, it will put Col1 and Col2 in the same group.
How can I do a SUM of records based on Group Col1 ?
I have this so far: http://sqlfiddle.com/#!3/eada2/1
Thank you
I was able to solve it as follows:
WITH cteActivityIds (activityId, allDocuByActivity)
AS
(SELECT activityId, COUNT(*) AS allDocuByActivity FROM #ER GROUP BY activityId)
SELECT
E.activityId AS [Actiivty ID],
docuType AS [Docu Type],
COUNT(docuType),
CONVERT(DECIMAL(16,2), (COUNT(docuType) * 100.00 / t.allDocuByActivity)) [Total DocuType in Activity],
SUM(CASE WHEN [sent] != '1-1-1900' THEN 1 END) AS [Sent],
SUM(CASE WHEN [approved] != '1-1-1900' THEN 1 END) AS [Approved]
FROM
#ER AS E
INNER JOIN cteActivityIds AS t
ON E.activityId = t.activityId
GROUP BY
E.activityId, docuType, t.allDocuByActivity
Thanks
Here is a solution that, in my opinion, looks a little cleaner - it does not require a join and uses 'partition by' to calculate the individual counts:
WITH activityCounts as (
select
activityId,
docuType,
count(activityId) OVER(PARTITION BY activityId) as activityIdCount,
count(docuType) OVER(PARTITION BY activityId, docuType) as docuTypeCount,
SUM(CASE WHEN [sent] != '1-1-1900' THEN 1 END) OVER(PARTITION BY activityId, docuType) AS [Sent],
SUM(CASE WHEN [approved] != '1-1-1900' THEN 1 END) OVER(PARTITION BY activityId, docuType) AS [Approved]
from ER
)
SELECT
activityId,
docuType,
docuTypeCount,
CONVERT(DECIMAL(16,2), (COUNT(docuTypeCount) * 100.00 / activityIdCount)) as [Total DocuType in Activity],
[Sent],
[Approved]
FROM activityCounts
GROUP BY
activityId,
docuType,
activityIdCount,
docuTypeCount,
[Sent],
[Approved]
Here is a link to sqlfiddle
You just need to put an aggregate function on t.allDocuByActivity
MIN(t.allDocuByActivity) AS [Total DocuType in Activity],
However, since your label is DocuType. Don't you need DISTINCT?
I'm creating a stored procedure pulling aggregate sum values from a few different tables. Separately, the queries are simplistic with different filters.
The queries need to be joined together and are as follows:
select distinct(bus_name), sum(act) as 'totrev', sum(budget) as 'budget rev'
from finance
where year = '2011'
and type_desc = 'rev'
group by bus_code, bus_name
order by bus_name asc
select distinct(bus_name), sum(act) as 'totalexp', sum(budget) as 'budget exp'
from finance
where year = '2011'
and type_desc = 'exp'
group by bus_code, bus_name
order by bus_name asc
select distinct(bus_name), sum(end_balance) as 'total assets'
from Balance
where year = '2011'
and type_desc = 'assets'
group by bus_code, bus_name
order by bus_name asc
select distinct(bus_name), sum(end_balance) as 'Cash'
from Balance
where year = '2011'
and type_desc = 'equity'
group by bus_code, bus_name
order by bus_name asc
select bus_code, bus_name, count(bus_code) as '#of bldgs'
from building
group by bus_code, bus_name
order by bus_name asc
I'm looking to merge/join all the columns to be viewed essentially in one table.
finance_table
columns = bus_code, bus_name, # of bldgs, tot_rev, budget_rev, totalexp, budget exp, total assets, cash
Try something like this by using nested queries:
SELECT T5.bus_code, T5.bus_name, T5.[# of bldgs], T1.tot_rev, T1.budget_rev, T2.totalexp, T2.[budget exp], T3.[total assets], T4.cash
FROM
(
select distinct(bus_name), sum(act) as 'totrev', sum(budget) as 'budget rev'
from finance
where year = '2011'
and type_desc = 'rev'
group by bus_code, bus_name
order by bus_name asc
) T1 INNER JOIN
(
select distinct(bus_name), sum(act) as 'totalexp', sum(budget) as 'budget exp'
from finance
where year = '2011'
and type_desc = 'exp'
group by bus_code, bus_name
order by bus_name asc
) T2 ON T1.bus_name = T2.bus_name
INNER JOIN
(
select distinct(bus_name), sum(end_balance) as 'total assets'
from Balance
where year = '2011'
and type_desc = 'assets'
group by bus_code, bus_name
order by bus_name asc
) T3 ON T2.bus_name = T3.bus_name
INNER JOIN
(
select distinct(bus_name), sum(end_balance) as 'Cash'
from Balance
where year = '2011'
and type_desc = 'equity'
group by bus_code, bus_name
order by bus_name asc
) T4 ON T3.bus_name = T4.bus_name
INNER JOIN
(
select bus_code, bus_name, count(bus_code) as '#of bldgs'
from building
group by bus_code, bus_name
order by bus_name asc
) T5 ON T4.bus_name = T5.bus_name
I assume inner joins, but you may need to use outer joins if some of these won't have an entry for a particular business. But the general technique would be the same.
If your SQL supports CASE expressions, you can use them to create "virtual" fields for each type, and then sum these up.
select bus_code, bus_name
,sum(case when type_desc = 'rev' then act else 0 end) as 'totrev'
,sum(case when type_desc = 'rev' then budgetelse 0 end) as 'budget rev'
,sum(case when type_desc = 'exp' then act else 0 end) as 'totexp'
,sum(case when type_desc = 'exp' then budgetelse 0 end) as 'budget exp'
... ... etc.
from finance
where year = '2011'
group by bus_code, bus_name
order by bus_name asc
The last (building) table can simple be joined to this one, on bus-code