sum distinct value while using distinct id - sql

I am working on a data that looks like this:
from the table the gender (M,F) has the same globalid, however, I need to sum the distinct globalid's value column based on the gender (total from M and F).
I have tried this code but the query just returned the same data.
select distinct (globalid) globalid, fcname, featureidentifier,
gender, source, wardcode,sum (distinct value)
from public.kano_pp
source= 'Worldpop / ORNL Adjusted'
group by globalid, fcname, featureidentifier,gender, source, wardcode, value
order by globalid;

I think you want something more like this:
select globalid,
sum(case when gender = 'F' then value else 0 end) as female_value,
sum(case when gender = 'M' then value else 0 end) as male_value
from public.kano_pp
where source = 'Worldpop / ORNL Adjusted'
group by globalid
order by globalid;
The more recent versions of Postgres support the filter clause which is a bit more efficient than the sum(case . . ).

Related

Is There a Way to Automate the Conversion of SQL Rows to Column Using Case?

I was playing with usa_names dataset on Bigquery and in order to be able to visualize the top 10 names between 1910 and 2020, I had to GROUP BY year and create a new column for each of the 10 names using CASE.
The thing is, I will like to visualize the top 100 and I want to know if there is a way to automate the CASE, in the sense that I don't have to write a "WHEN and THEN Clause for each name in order to create a column for them.
I had to use the following SQL query code to first get the top 10 names;
SELECT
name,
SUM(number) AS total
FROM
bigquery-public-data.usa_names.usa_1910_current
WHERE
year BETWEEN 1910 AND 2020
GROUP BY
name
ORDER BY
total DESC
LIMIT
10
And then use the following code to convert each name row to columns;
SELECT
year,
SUM(CASE WHEN name = 'James' THEN number ELSE 0 END) AS James,
SUM(CASE WHEN name = 'John' THEN number ELSE 0 END) AS John,
SUM(CASE WHEN name = 'Robert' THEN number ELSE 0 END) AS Robert,
SUM(CASE WHEN name = 'Michael' THEN number ELSE 0 END) AS Michael,
SUM(CASE WHEN name = 'William' THEN number ELSE 0 END) AS William,
SUM(CASE WHEN name = 'Mary' THEN number ELSE 0 END) AS Mary,
SUM(CASE WHEN name = 'Richard' THEN number ELSE 0 END) AS Richard,
SUM(CASE WHEN name = 'Joseph' THEN number ELSE 0 END) AS Joseph,
SUM(CASE WHEN name = 'Charles' THEN number ELSE 0 END) AS Charles,
SUM(CASE WHEN name = 'Thomas' THEN number ELSE 0 END) AS Thomas
FROM
bigquery-public-data.usa_names.usa_1910_current
GROUP BY
year
ORDER BY
year
I want to achieve the same result without having to first pull out the name and manually enter them into the CASE statements.
Also, this won't be needed if there is a way to visualize the data directly without having to convert the names from row to columns.
Thanks.
You need to combine 2 capabilities:
row to column: PIVOT clause
scripting to automate the query finding the top 10 names
declare top_names default ((
select concat("'", string_agg(name, "','"), "'")
from (
// your query in question
SELECT
name
FROM
bigquery-public-data.usa_names.usa_1910_current
WHERE
year BETWEEN 1910 AND 2020
GROUP BY
name
ORDER BY
SUM(number) DESC
LIMIT
10
)));
select top_names;
The output is:
'James','John','Robert','Michael','William','Mary','David','Richard','Joseph','Charles'
The PIVOT query you will need is:
SELECT * FROM
(select year, name, sum(number) number
from bigquery-public-data.usa_names.usa_1910_current
group by year, name
)
PIVOT(SUM(number) FOR name IN ('James','John','Robert','Michael','William','Mary','David','Richard','Joseph','Charles'
))
which output exactly as your second query.
To stick the 2 together, you will need something like:
execute immediate concat(
"""
SELECT * FROM
(select year, name, sum(number) number
from bigquery-public-data.usa_names.usa_1910_current
group by year, name
)
PIVOT(SUM(number) FOR name IN (
""",
top_names,
"))");
You shouldn't need to create a column for each name. Your first query is sufficient (would obviously just need to change the limit to 100). Based on the questions tags I'm assuming your using Tableau, so it would be as simple as choosing your desired visualisation (say a bar chart) and placing names on one axis and total on the other axis.
Based on your follow up comment it would look like this
SELECT
name,
year,
SUM(number) AS total
From bigquery-public-data.usa_names.usa_1910_current
WHERE name IN
(
SELECT name
FROM
(
SELECT
name,
SUM(number) AS total
FROM
bigquery-public-data.usa_names.usa_1910_current
WHERE
year BETWEEN 1910 AND 2020
GROUP BY
name
ORDER BY
total DESC
LIMIT
100
))
GROUP BY name, year
You could also look into using calculate fields within Tableau ok the raw data to achieve the desired visualisation.

How to create a column based on condition of a column value contain in SQL?

I want to create category column based on value of measure type column,
i.e. if any of the value of measure type corresponding to sr_num has dispatches then i want it to
categorize as D and if it has activities then categorize as A
I have tried below, but it didnt work:
select t*,
case when measuretype = 'dispatches' then 'D'
else 'A' end as category
from t
You can use window functions. One method is:
select t.*,
(case when sum(case when measureType = 'Dispatches' then 1 else 0 end) over (partition by sr_num) > 0
then 'D' else 'A'
end) as category
from t;
Or, given your sample data, you can use this simpler version:
select t.*,
max(left(measureType, 1)) over (partition by sr_num) as category
from t;

BigQuery(standard SQL) grouping values based on first CASE WHEN statement

Here is my query with the output below the syntax.
SELECT DISTINCT CASE WHEN id = 'RUS0261431' THEN value END AS sr_type,
COUNT(CASE WHEN id in ('RUS0290788') AND value in ('1','2','3','4') THEN respondentid END) AS sub_ces,
COUNT(CASE WHEN id IN ('RUS0290788') AND value in ('5','6','7') THEN respondentid END) AS pos_ces,
COUNT(*) as total_ces
FROM `some_table`
WHERE id in ( 'RUS0261431') AND id <> '' AND value IS NOT NULL
GROUP BY 1
As you can see with the attached table I'm unable to group the values based on Id RUS0290788 with the distinct values that map to RUS0261431. Is there anyway to pivot with altering my case when statements so I can group sub_ces and pos_ces by sr_type. Thanks in advanceenter image description here
You can simplify your WHERE condition to WHERE id = ('RUS0261431'). Only records with this value will be selected so you do not have to repeat this in the CASE statements.

SQL query - group by string prefix

I'm struggling with a grouping query.
I have simple table named CarParts where some car elements stored in it.
Some of those elements are available (with Type prefix "05") and some are blocked (Type prefix "01").
I want to write select query that would group my table CarParts by SerialNr and Type as shown below on the right side.
Do you want conditional aggregation?
select serialnr, name,
sum(case when type like '%-05' then amount else 0 end) as [05-available],
sum(case when type like '%-01' then amount else 0 end) as [01-blocked]
from carparts
group by serialnr, name;
You can use PIVOT to get your desired result as below-
SELECT SerialNr,
ISNULL([05-Available],0) [05-Available],
ISNULL([01-Available],0) [01-Available],
Name
FROM
(
SELECT SerialNr,Amount,Name,RIGHT( Type,2) +'-Available' AS P_Column
FROM CarParts
) AS P
PIVOT
(
SUM(Amount)
FOR P_Column IN ([01-Available],[05-Available])
) AS PVT
you can use case when
select SerialNr,Name,
sum(case when right([Type],2)='01' then amount else 0 end) as blocked_01
sum(case when right([Type],2)='05' then amount else 0 end) as availabe_05
from tbale_name group by SerialNr,Name
select SerialNr,
sum(case when Type like '%-05' then Amount else 0 end) as '05-available',
sum(case when Type like '%-01' then Amount else 0 end) as '01-blocked',
Name
from carparts
group by SerialNr, Name

Specific where for multiple selects

I have the following problem:
I have a table that looks something like this:
ArticleID|Group|Price
1|a|10
2|b|2
3|a|3
4|b|5
5|c|5
6|f|7
7|c|8
8|x|3
Now im trying to get a result like this:
PriceA|PriceRest
13|30
Meaning I want to sum all prices from group a in one column and the sum of everything else in another column.
Something like this doesnt work.
select
sum(Price) as PriceGroupA
sum(Price) as PriceRest
from
Table
where
Group='a'
Group<>'a'
Is there a way to achieve this functionality?
SELECT
sum(case when [Group] = 'a' then Price else 0 end) as PriceA,
sum(case when [Group] <> 'a' then Price else 0 end) as PriceRest
from
Table
Please try:
select
sum(case when [Group]='A' then Price end) PriceA,
sum(case when [Group]<>'A' then Price end) PriceRest
from
Table
SQL Fiddle Demo
You just need two sub-queries:
SELECT (SELECT SUM(PRICE)
FROM Table1
WHERE [Group] ='a') AS PriceGroupA,
(SELECT SUM(PRICE)
FROM Table1
WHERE [Group]<>'a') AS PriceRest
Demo-Fiddle