SQL Melt after Mapping Columns - sql

I have the following working query:
SELECT
postgres."week" AS "week",
CASE
WHEN (postgres."spent_money_office") = 1 THEN (postgres."weight")
WHEN (postgres."spent_time_office") = 1 THEN (postgres."weight")
WHEN (postgres."spent_other_office") = 1 THEN (postgres."weight")
ELSE 0
END AS "office_leisure",
CASE
WHEN (postgres."spent_money_home") = 1 THEN (postgres."weight")
WHEN (postgres."spent_time_home") = 1 THEN (postgres."weight")
WHEN (postgres."spent_other_home") = 1 THEN (postgres."weight")
ELSE 0
END AS "home_leisure",
CASE
WHEN (postgres."spent_money_vacation") = 1 THEN (postgres."weight")
WHEN (postgres."spent_time_vacation") = 1 THEN (postgres."weight")
WHEN (postgres."spent_other_vacation") = 1 THEN (postgres."weight")
ELSE 0
END AS "vacation_leisure"
FROM
"lake"."postgres" AS "postgres"
GROUP BY
1,
2,
3,
4
ORDER BY
1
Which gives 4 columns: week, office_leisure, home_leisure, and vacation_leisure as shown here:
I would like to "melt" the leisure columns into one called leisure_type taking on 3 values, either office/home/vacation and another column called weight. How can this be done using the SQL code query above?
Something like:
week
leisure_type
weight
week 1
office
1.78
week 1
home
1.78
week 1
vacation
1.78
week 1
office
0
...
...
...

You can apply a union over the selection of the week, leisure type and leisure value, for each leisure type you have (so three times):
SELECT week,
'office_leisure' AS leisure_type,
office_leisure AS weight
FROM tab
UNION
SELECT week,
'home_leisure' AS leisure_type,
home_leisure AS weight
FROM tab
UNION
SELECT week,
'vacation_leisure' AS leisure_type,
vacation_leisure AS weight
FROM tab
You can find a fiddle here.

Related

SQL query select returns different result than expected

I'm querying on this 2 tables:
TIMBRATURE
ASSELEMGEN
This is my query:
select convert(varchar(11),convert(date,datav),105) as data,
sum (CASE WHEN idterminale=3 and DATEPART(hour,datav)>='9' and DATEPART(hour,datav)<='16' THEN 1 ELSE 0 END) as pranzoP,
sum (CASE WHEN idterminale=3 and DATEPART(hour,datav)>='17' and DATEPART(hour,datav)<='23' THEN 1 ELSE 0 END) as cenaP,
sum (CASE WHEN idterminale=3 THEN 1 ELSE 0 END) as totaleP
from TIMBRATURE where DATAV>=#dataDa and DATAV<#primoGGmeseSuccessivo and TIMBRATURE.IDDIP
in (select iddip from ASSELEMGEN where IDELEM=1001)
group by convert(date,datav)
order by convert(date,datav)
For this purpose consider this argumets:
declare #datada as date='20230201'
declare #primoggmesesuccessivo as date='20230207'
The result I get:
Iddip is user ID, problem is when user have 2 entries for the same day, one with datav hour part between 9 and 16, the other between 17 and 23. In this case I have to count 2 for it, but my query only count it once. For example in the result above on 1th February I expect PranzoP=93 and totaleP=130.

SQL query to aggregate month in one table

I have a table with one column (TK) with multiple values, also duplicated and another one column with date.
I need to return a table with first column with distinct(TK) and the other columns like month.
I do an example into SQL FIDDLE
http://sqlfiddle.com/#!18/14cb9f/28
TK
JANUARY
open a
4
open B
4
TK
FEBRUARY
open a
4
open B
4
I need
TK
JANUARY
FEBRUARY
open a
4
4
open B
4
4
Thanks
A simple conditional aggregation should do the trick
SELECT TK
,Janary = sum( case when month(datastart)=1 then 1 else 0 end )
,February = sum( case when month(datastart)=2 then 1 else 0 end )
From TEST
Where year(datastart)=2021
Group By TK
Or you can use PIVOT
Select *
From (
Select TK
,Col = datename(month,DataStart)
,Val = 1
From TEST
Where year(datastart)=2021
) src
Pivot ( sum(Val) for Col in ([January] ,[February] ) ) pvt
There are multiple ways to do this, but avoiding sub-queries and making the syntax simple to read, this is the simplest I can get:
SELECT
TK,
SUM(
CASE WHEN DATASTART >= '2021-01-01' AND DATASTART < '2021-02-01' THEN 1 ELSE 0 END
) AS JENUARY,
SUM(
CASE WHEN DATASTART >= '2021-02-01' AND DATASTART <= '2021-02-28' THEN 1 ELSE 0 END
) AS FEBRUARY
FROM
Test
GROUP BY
TK
Check it out
http://sqlfiddle.com/#!18/14cb9f/34

Case When bringing back two lines rather than one

Hi all I have some code I'm working on, and what I need to do I'm sure is relatively easy, however I'm struggling on a Case statement
What I need to do;
Bring back the data set to make into a table within SSRS, split by Year, then Usage Month, then by Billing Tier
Issue;
Billing Tiers are 0,1,4,5
0 is historic data and I need to show this as 1, then add 0 and original tier 1 together
What I've done so far;
DECLARE #UsageMonth DATE = '20170401'
DECLARE #YEAR INT = '2017'
DECLARE #BillingTier2 INT = 1;
SELECT YEAR(UsageMonth) AS [Year],
UsageMonth,
--Billingtier,
CASE WHEN billingtier = 0 THEN 1 ELSE billingtier END AS BillingTier2,
SuppliesBilled = COUNT(DISTINCT c.CoreMPAN),
CreditKwH = SUM(CASE WHEN c.IsCredit = 1 THEN c.ConsumptionUnits ELSE 0 END),
DebitKwH = SUM(CASE WHEN c.IsCredit = 0 THEN c.ConsumptionUnits ELSE 0 END),
TotalKwh = SUM(c.ConsumptionUnits),
CreditAmount = SUM(CASE WHEN c.IsCredit = 1 THEN c.ConsumptionAmount ELSE 0 END),
DebitAmount = SUM(CASE WHEN c.IsCredit = 0 THEN c.ConsumptionAmount ELSE 0 END),
TotalAmount= SUM(c.ConsumptionAmount),
UnitRate = SUM(c.ConsumptionAmount) / NULLIF(SUM(c.ConsumptionUnits), 0),
StandingCharge = SUM(c.StandingChargeAmount),
CCL = SUM(c.CCLAmount)
FROM dbo.table1 c
WHERE YEAR(UsageMonth) = #YEAR
AND UsageMonth = #UsageMonth
GROUP BY YEAR(UsageMonth), UsageMonth, Billingtier, CASE WHEN billingtier = 0 THEN 1 ELSE billingtier END
The issue I have here is that this brings back both all columns that were previously 0 as 1 on one line, as well as another line where billing tier is actually 1, thus giving me two lines for '1', where it should be one line with both billing tier 1 and 0 added together
Data Expected
Year UsageMonth BillingTier2 SuppliesBilled CreditKwH DebitKwH TotalKwh CreditAmount DebitAmount TotalAmount UnitRate StandingCharge CCL
2017 01/04/2017 1 3296 -4348786.008 7219573.706 2870787.699 -523979.1005 866478.4812 342499.3807 0.238118 22394.5114 10685.7546
2017 01/04/2017 4 27 -59415.7663 65843.4963 6427.73 -9269.5841 10359.9353 1090.3512 0.169632 118.5181 21.3836
2017 01/04/2017 5 515 -524035.4192 943647.2675 419611.8483 -105349.1449 189478.524 84129.3791 0.200493 6581.5 1567.7762
Data receiving
Year UsageMonth BillingTier2 SuppliesBilled CreditKwH DebitKwH TotalKwh CreditAmount DebitAmount TotalAmount UnitRate StandingCharge CCL
2017 01/04/2017 1 3124 -4348786.008 7219573.706 2870787.699 -523979.1005 866478.4812 342499.3807 0.119305 22394.5114 10685.7546
2017 01/04/2017 4 27 -59415.7663 65843.4963 6427.73 -9269.5841 10359.9353 1090.3512 0.169632 118.5181 21.3836
2017 01/04/2017 5 515 -524035.4192 943647.2675 419611.8483 -105349.1449 189478.524 84129.3791 0.200493 6581.5 1567.7762
As you can see, all the sums and data match, bar the Supplies billed as 0 originally (172) missing from the Case statement when counted
Any help here would be greatly appreciated
Cheers
As you are using DISTINCT inside the COUNT function as below-
SuppliesBilled = COUNT(DISTINCT c.CoreMPAN)
Its decreasing the number of COUNT if there are multiple c.CoreMPAN avilable with same value. Hoe you are aware of it. If this is not expected, you can try with removing the DISTINCT command from COUNT as below-
SuppliesBilled = COUNT(c.CoreMPAN)

Using COUNT CASE WHEN MONTH Statement in MariaDB 10.2.15

I created a query to calculate the Amount of Id in a table using COUNT, CASE, WHEN and MONTH ..
Code:
SELECT
COUNT(CASE WHEN MONTH(LogsFormatted.DateIn) = 1 THEN LogsFormatted.Id ELSE 0 END ) AS '1',
COUNT(CASE WHEN MONTH(LogsFormatted.DateIn) = 2 THEN LogsFormatted.Id ELSE 0 END ) AS '2'
FROM
HrAttLogsFormatted AS LogsFormatted
WHERE
LogsFormatted.DateIn BETWEEN '2019-01-01' AND '2019-02-31'
AND LogsFormatted.Late != ''
Output :
| 1 | 2 |
| 1378 | 1378 |
The output I want to make is to calculate the Id in each month, namely Month 1 and Month 2
| 1 | 2 |
| 792 | 586 |
The data above is a fact
Using the above query instead adds up between the results of calculating month 1 and month 2
You should be counting NULL when the criteria in your CASE expression does not match. Also, I prefer counting 1 unless you really want to the count the Ids themselves. This version should work:
SELECT
COUNT(CASE WHEN MONTH(lf.DateIn) = 1 THEN 1 END) AS '1',
COUNT(CASE WHEN MONTH(lf.DateIn) = 2 THEN 1 END) AS '2'
FROM HrAttLogsFormatted AS lf
WHERE
lf.DateIn BETWEEN '2019-01-01' AND '2019-02-31' AND
lf.Late != '';
Note carefully that the current counts you are seeing sum up to the individual counts, that is:
1378 = 792 + 586
The reason for this is the the COUNT function "counts" any non NULL value as 1, and any NULL value as zero. Your current CASE expression will always count 1, for every record in the table.
remove else part from case when expression - if you use else with 0 then count takes that also in consideration which gives u actually wrong ouput
SELECT
COUNT(CASE WHEN MONTH(LogsFormatted.DateIn) = 1 THEN LogsFormatted.Id END ) AS '1',
COUNT(CASE WHEN MONTH(LogsFormatted.DateIn) = 2 THEN LogsFormatted.Id END ) AS '2'
FROM
HrAttLogsFormatted AS LogsFormatted
WHERE
LogsFormatted.DateIn BETWEEN '2019-01-01' AND '2019-02-31'
AND LogsFormatted.Late != ''
If you are using MariaDB, I would just use SUM() with a boolean:
SELECT SUM( MONTH(lf.DateIn) = 1 ) as month_1,
SUM( MONTH(lf.DateIn) = 2 ) as month_2
FROM HrAttLogsFormatted lf
WHERE lf.DateIn >= '2019-01-01' AND
lf.DateIn < '2020-01-01' AND
lf.Late <> '';
This assumes that the id that you are counting is never NULL (a reasonable assumption for an id).
Note other changes:
The column aliases do not need to be escaped. Don't use non-standard names, unless you need them -- for some reason -- for downstream processing.
This uses a shorter table alias, so the query is easier to write and to read.
The date comparisons use inequalities, so this works both for dates and datetimes.
<> is the standard SQL comparison operator for inequality.

Case Function in Oracle - wrong return

I have an table with these fields:
id,
quarter,
description,
id_school.
These table have this data:
ID | quarter | description
12 A 1 YEAR
12 S 1 Year
12 A DONE
I want to get the serie_school based on the below query:
select NVL(
case
WHEN quarter = 'S' AND
(UPPER(description ) LIKE 'DONE' OR
UPPER(description ) LIKE '%YEAR' OR
UPPER(description ) LIKE 'LANGUAGE') THEN -1
WHEN quarter = 'A' AND
(UPPER(description ) LIKE 'DONE' OR
UPPER(description ) LIKE '%QUARTER' OR
UPPER(description ) LIKE '%STEP' OR
UPPER(description ) LIKE 'LANGUAGE') THEN -1
WHEN quarter = 'T' THEN -1
ELSE -1
end, -1) nvl_return from test
The return of this on my query is:
ID | quarter | description | nvl_return
12 A 1 YEAR 1
12 S 1 Year 1 *- (this column has the wrong answer)*
12 A DONE -1
The answer of line 2 is wrong, because the QUARTER field is 'S' and the description field have 'year', so it needs to be -1, but in Oracle is returning 1.
Is there anyone who can help me with this?
Thanks in advance
Alexandre,
Examine your statement, where I have added "<======" to point out the various possible amounts for this column.
select NVL(
case
WHEN quarter = 'S' AND
(UPPER(description ) LIKE 'DONE' OR
UPPER(description ) LIKE '%YEAR' OR
UPPER(description ) LIKE 'LANGUAGE') THEN -1<=======
WHEN quarter = 'A' AND
(UPPER(description ) LIKE 'DONE' OR
UPPER(description ) LIKE '%QUARTER' OR
UPPER(description ) LIKE '%STEP' OR
UPPER(description ) LIKE 'LANGUAGE') THEN -1<======
WHEN quarter = 'T' THEN -1 <======
ELSE -1 <=======
end, -1 <-this will never happen) nvl_return from test
You return "-1" in every single case. "-1" is the only value returned, by the only column returned in your query.
So when you say the results are:
ID | quarter | description | nvl_return
12 A 1 YEAR 1
12 S 1 Year 1 *- (this column has the wrong answer)*
12 A DONE -1
Unfortunately, your query cannot produce the results you've stated.
Try creating a SQL fiddle, to explain the issue. SQL Fiddle