SQL pivot columns null (code/results included) - sql

I have been playing with the SQL Fiddle, and am very close to being done - I just want some help on getting the column data returned ( I think the column varchar title with two words (example: High Value) is throwing it off.
This is query I'm struggling with:
SELECT Velocity
, [Very High]
, High
, [Medium]
, [Low]
, [Very Low]
, [Total]
FROM (
SELECT CASE
WHEN GROUPING(velocity) = 0 THEN CAST(velocity AS CHAR(7))
ELSE 'Total'
END AS velocity
, CASE
WHEN GROUPING(volume) = 0 THEN CAST(volume AS CHAR(7))
ELSE 'Total'
END AS volume
, SUM(Sales) AS Sales
FROM test1
GROUP BY velocity, volume
WITH CUBE
) AS s
PIVOT(SUM(Sales) FOR volume IN ([Very High], [High], [Medium], [Low], [Very Low], [Total])) AS p;
I'm expecting to see this result:
Adding a SQL Fiddle

I've found mistake in your SQL query. You need to change CAST(volume AS CHAR(7)) to CAST(volume AS CHAR(12)) Otherwise you have in your inner temp table values like "Very Hi" and "Very Lo".

Related

MS Access aggregate function Query works on a single table but but not on multiple tables

This query works fine:
SELECT
SessionResults.Driver,
SUM( IIF( SessionResults.Place = 1, 1, NULL ) ) AS [Race Wins],
ROUND( AVG( SessionResults.Place ), 2 ) AS [Avg Race Pos],
SUM( SessionResults.TotalLaps ) AS [Total Laps]
FROM
SessionResults
GROUP BY
SessionResults.Driver;
This one does not:
SELECT DISTINCT
SessionResults.Driver,
( SUM( IIF( [SessionResults.Place] = 1, 1, NULL ) ) ) AS [Race Wins],
ROUND( AVG( SessionResults.Place ), 2 ) AS [Avg Race Placing],
ROUND( AVG( SegmentData.SegPlace ), 2 ) AS [Avg Heat Placing],
COUNT( SessionResults.TotalLaps ) AS [Total Laps],
EventHistory.TrackID AS [Track/Layout],
MAX( EventHistory.Date ) AS [Last Race]
FROM
SessionResults,
SegmentData,
EventHistory
WHERE
(
(
( SessionResults.EventID ) = EventHistory.EventID
AND
SegmentData.EventID = SessionResults.EventID
)
)
GROUP BY
SessionResults.Driver,
EventHistory.TrackID;
The second query produces excessive counts in the [Race Wins] column. The other columns appear to be accurate.
I know there are better ways to do this in newer Access versions but I'm not up to speed on those methods either.
What am I missing here? I messed with different Join options but couldn't get anything to work. Can this be done with Access? The version I'm running is very old, Access 2000, V9.
Again, a single table query seems to work fine. The data gets messed up in the [Race Wins] column when I extend the query to other tables within the same mdb file. The single table query produces a max of 36 wins in the Race Wins column. When the query is extended to multiple tables those numbers increase to well over 600 wins, which is not accurate.

SQL Columns to Rows- for a View

I have a view which has
ID INQCLASS INQDETAIL Period BAL
1233 GROSS water 12-3-2017 233.32
1233 GROSS ENergy 12-3-2017 122.00
ID,INQCLASS, Period is same. Except the INQDETAIL and BAL
I want to combine this into a single row which displays water and energy Bal.
Any Suggestions would be helpful. Thank you
SELECT ID,
INQCLASS,
Period,
MAX(CASE WHEN INQDETAIL = 'water' then BAL else 0 end) as WaterBal,
MAX(CASE WHEN INQDETAIL = 'ENergy' then BAL else 0 end) as ENergyBal
FROM View_Name
GROUP BY ID, INQLASS, Period
The case statement serves to show the BAL only when the condition is met. So with case alone, this would still return two rows for each item, but one would have a Waterbal value and no energybal value, and the other would be the reverse.
When you do GROUP BY, every field has to either be in the GROUP BY list (in this case, ID, INQCLASS, Period), or have an aggregate function like SUM, MAX, COUNT, etc. (in this case Waterbal and energyBal have aggregate functions).
The GROUP BY in this case collapses the common ID, INQLASS, Period into single rows, and then takes the largest (MAX) value for Waterbal and energyBal. Since one is always 0, it simply supplies the other one.
A simple pivot table ought to do it. As long as you know Inqdetail values ahead of time:
select ID,
INQCLASS,
[Period],
[Water] AS [Water Bal],
[Energy] as [Energy Bal]
from
(
select [ID],
[INQCLASS],
[INQDETAIL],
[Period],
[BAL]
from #util
) As Utilities
PIVOT
(
SUM([BAL])
FOR [inqdetail] IN ([Water],[Energy])
) AS Pvttbl
Try something like this:
SELECT INQDETAIL
, PERIOD
, SUM(BAL) AS energy_Bal
FROM your_view
WHERE INQDETAIL LIKE 'water'
GROUP BY INQDETAIL
, PERIOD;
Try this:
SELECT *
FROM
(SELECT * FROM #temp) AS P
PIVOT
(
max(bal) FOR INQDETAIL IN ([water], [ENergy])
) AS pv1

Adding total column and row to sql server pivot

I have a pivot table that I believe to be working. I want to add a total column and a total row to this pivot. Here is the code for the pivot table...
SELECT Month,
[N] AS Expected,
[R] AS Requested,
[T] AS Tires,
[U] AS Unexpected,
[D] AS Damage
FROM (
SELECT CustomerNo,
DATEPART(mm,InvoiceDate) AS Month,
[Type],
SUM(Total) AS Cost
FROM tbl_PM_History
WHERE (InvoiceDate >= #Start)
AND (InvoiceDate <= #End)
AND (CustomerNo = #Cust)
GROUP BY CustomerNo,
DATEPART(mm,InvoiceDate),
TYPE
) p
PIVOT (SUM(Cost) FOR [Type] IN ([N],[R],[T],[U],[D]))AS pvt
ORDER BY Month
Here's a fairly quick way (in programming time) to achieve what you want:
;
WITH details -- Wrap your original query in a CTE so as to encapsulate all your calculations
AS (
SELECT Month,
[N] AS Expected,
[R] AS Requested,
[T] AS Tires,
[U] AS Unexpected,
[D] AS Damage,
ISNULL([N],0) + ISNULL([R],0) + ISNULL([T],0) + ISNULL([U],0) + ISNULL([D], 0) as Total
FROM (
SELECT CustomerNo,
DATEPART(mm,InvoiceDate) AS Month,
[Type],
SUM(Total) AS Cost
FROM tbl_PM_History
WHERE (InvoiceDate >= #Start)
AND (InvoiceDate <= #End)
AND (CustomerNo = #Cust)
GROUP BY CustomerNo,
DATEPART(mm,InvoiceDate),
TYPE
) p
PIVOT (SUM(Cost) FOR [Type] IN ([N],[R],[T],[U],[D])) AS pvt
)
, summary // Use another CTE to add a total line, using UNION ALL
AS (
SELECT Month
, Expected,
, Requested
, Tires
, Unexpected
, Damage
, Total
, 0 as RecordCode
FROM details
UNION ALL
SELECT Null
, SUM(Expected)
, SUM(Requested)
, SUM(Tires)
, SUM(Unexpected)
, SUM(Damage)
, SUM(Total)
, 1
FROM details
)
SELECT Month -- Do your actual sorting.
, Expected,
, Requested
, Tires
, Unexpected
, Damage
, Total
FROM summary
ORDER by RecordCode, Month

SQL Server IF 0, add value for following date

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

Can we use same aggregate function more than once on same table field or column using Different filter conditions?

I want to use SUM() function on 'Amount' field in a query 4 times on a same field with different filters.
something like
SELECT Date1,CC,BU, SUM(Amount),SUM(Amount),SUM(Amount),SUM(Amount)
FROM MainTable<br>
GROUP BY CC,BU,Date1
Here
1st SUM(Amount) should be calculated when Mode='011' And Mode='012' from MainTable
2nd SUM(Amount) should be calculated when Mode like '03_' And Mode Like '05_' from MainTable
3rd SUM(Amount) should be calculated when Mode like '10_' from MainTable
4th SUM(Amount) should be calculated when (Mode !='011') and (Mode !='012') (Mode not Like '03_') and (Mode not Like '05_') from MainTable
How to make this happen? I have tried in many ways but couldn't get the result the way I wanted.
Please help me.
Thank you in advance.
You can use an aggregate function with a CASE:
SELECT Date1,
CC,
BU,
SUM(case when mode = '011' then Amount end) Mode011,
SUM(case when mode = '012' then Amount end) Mode012,
SUM(case when mode = '013' then Amount end) Mode013,
SUM(case when mode = '014' then Amount end) Mode014
FROM MainTable
GROUP BY CC,BU,Date1;
Or you can use the PIVOT function:
select date1, CC, BU,
[011] Mode011,
[012] Mode012,
[013] Mode013,
[014] Mode014
from
(
select date1, CC, BU, mode, amount
from maintable
) src
pivot
(
sum(amount)
for mode in ([011], [012], [013], [014])
) piv