Is there a way to Pivot Oracle SQL results to show 1 unique ID and the non null values in each column? - sql

I am an Oracle SQL beginner and I have an issue with the code below:
SELECT unique_id,
CASE
WHEN type LIKE 'E-%' THEN
'electric'
ELSE
null
END electric_flag,
CASE
WHEN type LIKE 'G-%' THEN
'gas'
ELSE
null
END gas_flag,
CASE
WHEN type LIKE 'W-%' THEN
'water'
ELSE
null
END water_flag,
CASE
WHEN type LIKE 'S-%' THEN
'wastewater'
ELSE
null
END wastewater_flag
FROM (SELECT unique_id, type, end_dt
FROM table
WHERE end_dt IS NULL)
Which gives me the following results:
My goal is to have the results show like this:
It's almost like I want to group the results by the id, ignore rows that are all null, but combine the rows that return with the flag into a single row.
Any help would be greatly appreciated!

Here's a pseudo-code:
SELECT
*
FROM
(
SELECT
unique_id,
CASE type WHEN LIKE 'E-%' THEN 'electric'
WHEN LIKE 'G-%' THEN 'gas'
WHEN LIKE 'W-%' THEN 'water'
WHEN LIKE 'S-%' THEN 'wastewater'
ELSE NULL
END flag
FROM {table}
WHERE end_dt IS NULL
)
PIVOT
(
MAX(flag)
FOR flag IN ('electric' electric_flag, 'gas' gas_flag, 'water' water_flag, 'wastewater' wastewater_flag)
)
Here's an Oracle SQL Fiddle

You're almost there;
Conditionals are needed but they should be aggregated
a Grouping By unique_id clause should be added during the aggregation
a subquery is not needed
using ELSE null cases are redundant
it's suitable to add a ROW_NUMBER() analytic function in order to generate a column with ordinal values
So, use the following SQL Select Statement of Conditional Aggregation :
SELECT ROW_NUMBER() OVER (ORDER BY unique_id) AS id,
MAX(CASE
WHEN type LIKE 'E-%' THEN
'electric'
END) AS electric_flag,
MAX(CASE
WHEN type LIKE 'G-%' THEN
'gas'
END) AS gas_flag,
MAX(CASE
WHEN type LIKE 'W-%' THEN
'water'
END) AS water_flag,
MAX(CASE
WHEN type LIKE 'S-%' THEN
'wastewater'
END) AS wastewater_flag
FROM t
WHERE end_dt IS NULL
GROUP BY unique_id
Demo

Related

Coalesce in duplicated values

I have a table like this:
And I want to transform for each value a column, to become something like this:
If I do a query like this:
Select "_sdc_source_key_id",
COALESCE(value='Integrity',null) as cia_security
,COALESCE (value='Confidentiality',null) as cia_conf
,COALESCE (value='Availability',null) as cia_availability
FROM
staging_jira.issues__fields__customfield_10420
where _sdc_source_key_id='201496'
That is my result, I have duplicated rows:
What should be the best solution to achieve my transformation?
Thanks a lot!
You can GROUP By "_sdc_source_key_id" and use MAX of your values
Select "_sdc_source_key_id",
MAX(COALESCE(value='Integrity',null)) as cia_security
,MAX(COALESCE (value='Confidentiality',null)) as cia_conf
,MSX(COALESCE (value='Availability',null)) as cia_availability
FROM
staging_jira.issues__fields__customfield_10420
where _sdc_source_key_id='201496'
GROUP BY "_sdc_source_key_id"
If your databse doesn't support MAX from boolean switch to Int
Select "_sdc_source_key_id",
MAX(CASE WHEN value='Integrity' THEN 1 ELSE null END) as cia_security
,MAX(CASE WHEN value='Confidentiality' THEN 1 ELSE null END) as cia_conf
,MSX(CASE WHEN value='Availability' THEN 1 ELSE null END) as cia_availability
FROM
staging_jira.issues__fields__customfield_10420
where _sdc_source_key_id='201496'
GROUP BY "_sdc_source_key_id"

find duplicate row in the same table and mark them in sql

I have table 'workadress' and it contain 6 columns:
work_ref,work_street ,work_zip,workTN,...
I want to find duplicate rows in the same table depending on:
If (work_street, work_zip) are duplicate together, then you should look at workTN. If it is the same then put value ' ok ', but if workTN is not the same, put 'not ok'. How can I do it with SQL?
Result like:
You can use window functions:
select t.*,
(case when min(workTn) over (partition by work_street, work_zip) =
max(workTn) over (partition by work_street, work_zip)
then 'ok' else 'not ok'
end) as result
from t;
I think just a simple group by and count should be enough to do the job like so:
select
t.*,
case when dups.dups = 1 then 'OK' else 'not OK' end
from my_table t
join (
select work_street, work_zip, count(distinct workTN) dups
from my_table
group by work_street, work_zip
) dups on dups.work_street = t.work_street amd dups.work_zip = t.work_zip

Is there a way to avoid columns from GROUP BY

My table has columns such as ID,Perdium and Location so I want to calculate all the perdiums given to an employee and the perdium share given in NY. The issue which I am facing is that SQL Server engine is throwing as error stating that location column isnt present in the GROUP BY clause(as needed in my use-case).If I include the location in the Group By clause I always get NYPerdiumShare as 1 which is not what I am expecting. Is there any workaround to this?
WITH CTE_Employee AS
(
SELECT ID,
SUM(Perdium) AS TotalPerdium,
CASE WHEN Location='NY' THEN SUM(Perdium) ELSE NULL END AS NYPerdium FROM EmployeePerdium
GROUP BY ID
)
SELECT ID,
TotalPerdium,
NYPerdium/TotalPerdium AS NYPerdiumShare
FROM CTE_Employee
You can eliminate the need to group by on anything other than ID by rewriting your query as follows to hide CASE inside an aggregate function:
WITH CTE_Employee AS (
SELECT
ID
, SUM(Perdium) AS TotalPerdium
, SUM(CASE WHEN Location='NY' THEN Perdium ELSE 0 END) AS NYPerdium
FROM EmployeePerdium
GROUP BY ID
)
SELECT
ID
, TotalPerdium
, NYPerdium/TotalPerdium AS NYPerdiumShare
FROM CTE_Employee
You don't need a cte here. Just use the sum window function.
SELECT DISTINCT
ID,
SUM(Perdium) OVER() as TotalPerdium
SUM(CASE WHEN Location='NY' THEN 1.0*Perdium ELSE 0 END) OVER(PARTITION BY ID)
/SUM(Perdium) OVER() AS NYPerdium
FROM EmployeePerdium

pivot table returns more than 1 row for the same ID

I have a sql code which I am using to do pivot. Code is as follows:
SELECT DISTINCT PersonID
,MAX(pivotColumn1)
,MAX(pivotColumn2) --originally these were in 2 separate rows)
FROM(SELECT srcID, PersonID, detailCode, detailValue) FROM src) AS SrcTbl
PIVOT(MAX(detailValue) FOR detailCode IN ([pivotColumn1],[pivotColumn2])) pvt
GROUP BY PersonID
In the source data the ID has 2 separate rows due to having its own ID which separates the values. I have now pivoted it and its still giving me 2 separate rows for the ID even though i grouped it and used aggregation on the pivot columns. Ay idea whats wrong with the code?
So I have all my possible detailCode listed in the IN clause. So I have null returned when the value is none but I want it all summarised in 1 row. See image below.
If those are all the options of detailCode , you can use conditional aggregation with CASE EXPRESSION instead of Pivot:
SELECT t.personID,
MAX(CASE WHEN t.detailCode = 'cas' then t.detailValue END) as cas,
MAX(CASE WHEN t.detailCode = 'buy' then t.detailValue END) as buy,
MAX(CASE WHEN t.detailCode = 'sel' then t.detailValue END) as sel,
MAX(CASE WHEN t.detailCode = 'pla' then t.detailValue END) as pla
FROM YourTable t
GROUP BY t.personID

Constructing A Query In BigQuery With CASE Statements

So I'm trying to construct a query in BigQuery that I'm struggling with for a final part.
As of now I have:
SELECT
UNIQUE(Name) as SubscriptionName,
ID,
Interval,
COUNT(mantaSubscriptionIdmetadata) AS SubsPurchased,
SUM(RevenueGenerated) as RevenueGenerated
FROM (
SELECT
mantaSubscriptionIdmetadata,
planIdmetadata,
INTEGER(Amount) as RevenueGenerated
FROM
[sample_internal_data.charge0209]
WHERE
revenueSourcemetadata = 'new'
AND
Status = 'Paid'
GROUP BY
mantaSubscriptionIdmetadata,
planIdmetadata,
RevenueGenerated
)a
JOIN (
SELECT
id,
Name,
Interval
FROM
[sample_internal_data.subplans]
WHERE
id in ('150017','150030','150033','150019')
GROUP BY
id,
Name,
Interval )b
ON
a.planIdmetadata = b.id
GROUP BY
ID,
Interval,
Name
ORDER BY
Interval ASC
The resulting query looks like this
Which is exactly what I'm looking for up to that point.
Now what I'm stuck on this. There is another column I need to add called SalesRepName. The resulting field will either be null or not null. If its null it means it was sold online. If its not null, it means it was sold via telephone. What I want to do is create two additional columns where it says how many were sold via telesales and via online. The sum total of the two columns will always equal the SubsPurchased total.
Can anyone help?
You can include case statements within aggregate functions. Here you could choose sum(case when SalesRepName is null then 1 else 0 end) as online and sum(case when SalesRepName is not null then 1 else 0 end) as telesales.
count(case when SalesRepName is null then 1 end) as online would give the same result. Using sum in these situations is simply my personal preference.
Note that omitting the else clause is equivalent to setting else null, and null isn't counted by count. This can be very useful in combination with exact_count_distinct, which has no equivalent in terms of sum.
Try below:
it assumes your SalesRepName field is in [sample_internal_data.charge0209] table
and then it uses "tiny version" of SUM(CASE ... WHEN ...) which works when you need 0 or 1 as a result to be SUM'ed
SUM(SalesRepName IS NULL) AS onlinesales,
SUM(NOT SalesRepName IS NULL) AS telsales
SELECT
UNIQUE(Name) AS SubscriptionName,
ID,
Interval,
COUNT(mantaSubscriptionIdmetadata) AS SubsPurchased,
SUM(RevenueGenerated) AS RevenueGenerated,
SUM(SalesRepName IS NULL) AS onlinesales,
SUM(NOT SalesRepName IS NULL) AS telesales
FROM (
SELECT SalesRepName, mantaSubscriptionIdmetadata, planIdmetadata, INTEGER(Amount) AS RevenueGenerated
FROM [sample_internal_data.charge0209]
WHERE revenueSourcemetadata = 'new'
AND Status = 'Paid'
GROUP BY mantaSubscriptionIdmetadata, planIdmetadata, RevenueGenerated
)a
JOIN (
SELECT id, Name, Interval
FROM [sample_internal_data.subplans]
WHERE id IN ('150017','150030','150033','150019')
GROUP BY id, Name, Interval
)b
ON a.planIdmetadata = b.id
GROUP BY ID, Interval, Name
ORDER BY Interval ASC