I have query (below) that show me data in the column "Monthly".
but I need to rewrite this query to cumulative sums as shows third column on picture.
How can I do it?
Thanks for any reply.
My current query:
select cast( ( Prodej.Ce_Jedn * Prodej.Mnoz ) / 1000 as numeric(15,2) ) as "Monthly" ,
YEAR( FAV.vatDate ) as "Rok" ,
month( FAV.VatDate ) as "Měsíc"
from Prodej
join FAKTVYDA FAV on FAV.Ci = PRODEJ.C_Fak
and FAV.Rada = PRODEJ.R_Fak
where YEAR(FAV.VATDate) > year(getdate())-3
and FAV.Rada in ('10','20','30','60')
and PRODEJ.C_Fak <> 0
and '#{Stredisko.ParameterValue}' = case Prodej.Str
when '' then FAV.Str
when '-' then FAV.Str
else Prodej.str
end
order by month(FAV.VatDate)
When you use a SUM-statement, the query also requires a GROUP BY-statement.
This is not included in the query above, so it won't work.
You can achieve that by using a SUM statement in front of the field you want summarized. Please see this post which provides a solution that should fit your problem.
select cast( ( Prodej.Ce_Jedn * Prodej.Mnoz ) / 1000 as numeric(15,2) ) as "Monthly" ,
YEAR( FAV.vatDate ) as "Rok" ,
month( FAV.VatDate ) as "Měsíc"
SUM(( Prodej.Ce_Jedn * Prodej.Mnoz ) / 1000 as numeric(15,2) ) as "Cumulative"
from Prodej
join FAKTVYDA FAV on FAV.Ci = PRODEJ.C_Fak
and FAV.Rada = PRODEJ.R_Fak
where YEAR(FAV.VATDate) > year(getdate())-3
and FAV.Rada in ('10','20','30','60')
and PRODEJ.C_Fak <> 0
and '#{Stredisko.ParameterValue}' = case Prodej.Str
when '' then FAV.Str
when '-' then FAV.Str
else Prodej.str
end
order by month(FAV.VatDate)
Hope that helps,
Chris
Related
I'd appreciate some help with this code, I'm getting a 'missing keyword' error. I've never used the Lag function before, so hopefully I using it correctly. Thanks for your help. Gav
CREATE VIEW GS_Date AS
SELECT
DATE_DATE,
DATE_FLAG,
CASE WHEN LAG ( DATE_FLAG) OVER ( ORDER BY DATE_DATE ) = '1' THEN DATE_STEP = ( LAG ( DATE_FLAG) OVER ( ORDER BY DATE_DATE ) ) + '1'
WHEN LAG ( DATE_FLAG) OVER ( ORDER BY DATE_DATE ) = '0' AND LAG ( DATE_FLAG) OVER ( ORDER BY DATE_DATE ) = '-1' THEN DATE_STEP = ( LAG ( DATE_FLAG) OVER ( ORDER BY DATE_DATE ) ) + '1'
ELSE DATE_STEP = LAG ( DATE_FLAG) OVER ( ORDER BY DATE_DATE ) END AS DATE_STEP
FROM DATE_GROUP
The problem is with the CASE expression; you were using LAG correctly.
Other points: Don't add strings like '1' and '-1' to numbers. Add numbers - you don't need the single quotes.
Also, if in a computation something is common and only the "last part" is different, you can use the CASE expression "at the end". Like below:
Note: On re-reading the original post, the formula needs to be more complicated (I didn't get it exactly right). Not changing the answer, since it still illustrates the same ideas I meant to share. BUT: Looking at the original post, there is a condition "when LAG = 0 and LAG = -1" - that can never be true. What was meant is probably "OR" instead of "AND". In the formula I wrote below, this means one more WHEN...THEN... branch.
LAG(DATE_FLAG) OVER (ORDER BY DATE)
+ CASE LAG(DATE_FLAG) OVER (ORDER BY DATE ) WHEN 1 THEN 1
WHEN 0 THEN -1
ELSE 0 END AS DATE_STEP
Further edit: Looking at it again, it seems when the flag is 1, 0 or -1 then we must add 1, otherwise add 0... then it's easier to use a "simple CASE expression" instead of a "searched CASE expression" as I did. Something like:
LAG(...) ...
+ CASE WHEN LAG(...) ... IN (-1, 0, 1) THEN 1
ELSE 0 END AS DATE_STEP
Try like this
CREATE VIEW GS_Date AS
SELECT DATE_DATE,
DATE_FLAG,
CASE
WHEN LAG(DATE_FLAG) OVER(ORDER BY DATE_DATE) = '1' THEN
(LAG(DATE_FLAG) OVER(ORDER BY DATE_DATE)) + '1'
WHEN LAG(DATE_FLAG) OVER(ORDER BY DATE_DATE) = '0' AND LAG(DATE_FLAG) OVER(ORDER BY DATE_DATE) = '-1' THEN
(LAG(DATE_FLAG) OVER(ORDER BY DATE_DATE)) + '1'
ELSE
LAG(DATE_FLAG) OVER(ORDER BY DATE_DATE)
END AS DATE_STEP
FROM DATE_GROUP
So you don't have to keep writing LAG( ... ) OVER ( ... ) statements, get the LAG value in a sub-query and then use CASE or DECODE in the outer query:
CREATE VIEW GS_Date AS
SELECT DATE_DATE,
DATE_FLAG,
DECODE(
DATE_STEP,
1, 2,
0, 1,
-1, 0,
DATE_STEP
) AS DATE_STEP
FROM (
SELECT DATE_DATE,
DATE_FLAG,
LAG ( DATE_FLAG ) OVER ( ORDER BY DATE_DATE ) AS DATE_STEP
FROM DATE_GROUP
)'
Also, your second WHEN clause will never be true:
WHEN LAG ( DATE_FLAG ) OVER ( ORDER BY DATE_DATE ) = '0'
AND LAG ( DATE_FLAG ) OVER ( ORDER BY DATE_DATE ) = '-1'
THEN ...
Since the value can never be both -1 and 0. I've assumed you meant to use OR rather than AND.
I have two tables Contact and Invoice linked by ContactId
Please see fiddle
I am selecting all the contact who have spend more than 2500 per any year and the query works fine.
I wanted it to display in a below format.
Any help on this please using sql-server. I can easily do this using crystal-report cross tab, but trying to do thing only using sql-server
You can PIVOT, then UNPIVOT your data from your original query to get it in the desired format:
WITH T AS
( SELECT c.ContactID,
ContactName = c.Name,
Year = DATEPART(YEAR, i.InvDate),
Invoices = CAST(COUNT(i.InvoiceID) AS FLOAT),
InvTotal = CAST(SUM(i.InvTotal) AS FLOAT)
FROM Invoice AS i
INNER JOIN dbo.Contact AS c
ON c.ContactID = i.InvContactID
GROUP BY c.ContactID, c.Name, DATEPART(YEAR, i.InvDate)
HAVING SUM(i.InvTotal) > 2000
)
SELECT ContactName = CASE WHEN pvt.Measure = 'InvTotal' THEN '' ELSE pvt.ContactName END,
pvt.Measure,
[2012] = ISNULL(pvt.[2012], 0),
[2013] = ISNULL(pvt.[2013], 0),
[2014] = ISNULL(pvt.[2014], 0)
FROM T
UNPIVOT
( Value
FOR Measure IN ([Invoices], [InvTotal])
) AS upvt
PIVOT
( SUM(Value)
FOR [Year] IN ([2012], [2013], [2014])
) AS pvt
ORDER BY pvt.ContactName, Measure;
Example on SQL Fiddle
I have this query:
SELECT `s`.`time` , SUM( s.love ) AS total_love, SUM( s.sad ) AS total_sad, SUM( s.angry ) AS total_angry, SUM( s.happy ) AS total_happy
FROM (`employee_workshift` AS e)
JOIN `workshift` AS w ON `e`.`workshift_uuid` = `w`.`uuid`
JOIN `shift_summary` AS s ON `w`.`uuid` = `s`.`workshift_uuid`
WHERE `s`.`location_uuid` = '81956feb-3fd7-0e84-e9fe-b640434dfad0'
AND `e`.`employee_uuid` = '3866a979-bc5e-56cb-cede-863afc47b8b5'
AND `s`.`workshift_uuid` = '8c9dbd85-18a3-6ca9-e3f3-06eb602b6f38'
AND `s`.`time` >= CAST( '18:00:00' AS TIME )
AND `s`.`time` <= CAST( '00:00:00' AS TIME )
AND `s`.`date` LIKE '%2014-03%'
My problem is it returns "NULL" but when I changed my 'end_time' to "23:59:59", it returned the right data. I've got an idea to pull the hour of both 'start_time' and 'end_time' and then insert it in a loop to get everything between them.
$time_start = 15;
$time_end = 03;
So it should produce: 15,16,17,18,19,20,21,22,23,00,01,02,03
Then I'll compare them all. But this would take a lot of line and effort than just simply using "BETWEEN". Or should I just use "in_array"? Have you encountered this? I hope someone could help. Thanks.
19:00 is certainly bigger then 00:00 - so your approach should not work.
Try using full timestamp (including date) to get all data you need.
Try to use this query. I don't know your data structure so check INNER JOIN between s and s1 tables. The join must be one row to one row - the difference only in date. Date of s1 rows must be earlier on 1 day than s table rows.
SELECT s.time , SUM( s.love ) AS total_love, SUM( s.sad ) AS total_sad, SUM( s.angry ) AS total_angry, SUM( s.happy ) AS total_happy
FROM (employee_workshift AS e)
JOIN workshift AS w ON e.workshift_uuid = w.uuid
JOIN shift_summary AS s ON w.uuid = s.workshift_uuid
JOIN shift_summary AS s1 ON (w.uuid = s.workshift_uuid AND CAST(s.date as DATE)=CAST(s1.date as DATE)+1)
WHERE s.location_uuid = '81956feb-3fd7-0e84-e9fe-b640434dfad0'
AND e.employee_uuid = '3866a979-bc5e-56cb-cede-863afc47b8b5'
AND s.workshift_uuid = '8c9dbd85-18a3-6ca9-e3f3-06eb602b6f38'
AND s1.time >= CAST( '18:00:00' AS TIME )
AND s.time <= CAST( '00:00:00' AS TIME )
AND s.date LIKE '%2014-03%'
I am writing this query in MSSQL Server Management Studio, and I have run into a mental road block. Let's say I have a few buildings and as they have come online I want to compare their production vs what they were forecasted, P_AMOUNT and F_AMOUNT. These are two separate databases combined into one with a query (The production db and forecast db that is).
So my problem here is. I want to select the peak production here along side the forecast each B_ID. Most of the buildings are like B_ID #2 and have a forecast amount, but occasionally there is one that does not. Like B_ID #1. How would I go about rolling the date one month forward for only the F_Date if the F_Amount = 0?
SELECT P1.B_ID, P1.P_DATE, P1.P_AMOUNT, F1.F_DATE, F1.F_AMOUNT
FROM DB1.Production P1
INNER JOIN DB2.Forecast F1
ON P1.DB_ID = F1.DB_ID
Use a nested select of the Forecast table so that you get the minimum forecast date after the production date that has a value, something like:
SELECT MIN(F1.F_DATE)
WHERE F1.F_DATE > P1.P_DATE
AND F1.F_AMOUNT > 0
There are a handful of ways to solve your problem. One way is to rank each row based on F_DATE and when the F_AMOUNT value is zero, to pull the next row. Since you did not specify a version of SQL Server, I used syntax that would work in SQL Server 2005 or later.
With RnkItems As
(
Select B_ID, P_DATE, P_AMOUNT, F_DATE, F_AMOUNT
, Row_Number() Over ( Order By F_DATE ) As Rnk
From SourceData
)
Select R.B_ID, R.P_DATE, R.P_AMOUNT
, R.F_DATE As [Original F_DATE]
, R.F_AMOUNT As [Original F_AMOUNT]
, Case R.F_AMOUNT
When 0 Then R1.F_DATE
Else R.F_DATE
End As F_DATE
, Case R.F_AMOUNT
When 0 Then R1.F_AMOUNT
Else R.F_AMOUNT
End As F_AMOUNT
From RnkItems As R
Left Join RnkItems As R1
On R1.Rnk = R.Rnk + 1
SQL Fiddle Version
If you are using SQL Server 2012, you can use the new Lead function:
Select B_ID, P_DATE, P_AMOUNT
, F_DATE As [Original F_DATE]
, F_AMOUNT As [Original F_AMOUNT]
, Case F_AMOUNT
When 0 Then Lead ( F_DATE, 1 ) Over ( Order By F_DATE )
Else F_DATE
End As F_DATE
, Case F_AMOUNT
When 0 Then Lead ( F_AMOUNT, 1 ) Over ( Order By F_DATE )
Else F_AMOUNT
End As F_AMOUNT
From SourceData
SQL Fiddle Version
The above two solutions rely on the stated requirement that you always go exactly one month ahead. If, however, you want to go the first month with a non-zero value (i.e., it could be multiple jumps), that's different:
Select S.B_ID, S.P_DATE, S.P_AMOUNT
, S.F_DATE As [Original F_DATE]
, S.F_AMOUNT As [Original F_AMOUNT]
, Case S.F_AMOUNT
When 0 Then (
Select Min( S2.F_DATE )
From SourceData As S2
Where S2.F_DATE >= S.F_DATE
And S2.F_AMOUNT <> 0
)
Else S.F_DATE
End As F_DATE
, Case S.F_AMOUNT
When 0 Then (
Select S1.F_AMOUNT
From SourceData As S1
Where S1.F_DATE = (
Select Min( S2.F_DATE )
From SourceData As S2
Where S2.F_DATE > S.F_DATE
And S2.F_AMOUNT <> 0
)
)
Else S.F_AMOUNT
End As F_AMOUNT
From SourceData As S
SQL Fiddle Version
SELECT YEAR, period, round((1- sum(rej_qty) / sum(recd_qty))*100, 0)
FROM TAB_A
WHERE sid = '200'
AND sdid IN ('4750')
AND
(
(
YEAR ='2011'
AND period IN('01_JAN')
)
OR
(
YEAR = '2010'
AND period IN('02_FEB','03_MAR','04_APR','05_MAY','06_JUN','07_JUL','08_AUG','09_SEP','10_OCT','11_NOV','12_DEC')
)
)
group by year, period
For a particular month, recd_qty is ZERO because of which I am getting DIVIDE BY ZERO error.
Is there any way to avoid DIVIDE BY ZERO error?
I there any way where in that particular month is ignored?
Have you tried using NULLIF()?
SELECT
( 100 / NULLIF( 0, 0 ) ) AS value
;
Oracle Doc
http://www.oracle-base.com/articles/9i/ANSIISOSQLSupport.php#NULLIFFunction
Another example
http://www.bennadel.com/blog/984-Using-NULLIF-To-Prevent-Divide-By-Zero-Errors-In-SQL.htm
If you want to ignore such records you can use a subquery
SELECT YEAR, period, round((1- rej_sum / recd_sum)*100, 0) FROM
(
SELECT YEAR, sum(rej_qty) rej_sum, sum(recd_qty) recd_sum
FROM TAB_A
WHERE sid = '200'
AND sdid IN ('4750')
AND
(
(
YEAR ='2011'
AND period IN('01_JAN')
)
OR
(
YEAR = '2010'
AND period IN ('02_FEB','03_MAR','04_APR','05_MAY','06_JUN','07_JUL','08_AUG','09_SEP','10_OCT','11_NOV','12_DEC')
)
)
group by year, period
)
WHERE recd_sum <> 0;
If you want to keep them and handle the division by zero issue, you can use decode or case
SELECT YEAR, period, DECODE(recd_qty, 0, NULL, round((1- sum(rej_qty) / sum(recd_qty))*100, 0))
round(ISNULL(
((1- sum(rej_qty)) / NULLIF( (sum(recd_qty))*100), 0 )),
0
),0)
If you replace your division using NULLIF to set a NULL when there is divide by zero, then an ISNULL to replace the NULL with a 0 - or indeed whatever value you want it to.
CASE WHEN sum(recd_qty) <> 0 THEN round((1- sum(rej_qty) / sum(recd_qty))*100, 0) ELSE 0 END