table : metrics
columns:
1. name : Name
2. instance: A name can have several instances
(Name: John, Instances: John at work, John at concert)
3. metric: IQ, KQ, EQ
4. metric_value: Any numeric
Objective of the query
Find out the metrics whose metric_value is 0 for all instances for all names.
Nature of data
A name's metric 'M' for instance 'X' could be 10. But for the same name and the same metric instance 'Y' could be 0. In this case, 'M' should NOT be returned.
Edit:
Sample data:
NAME INSTANCE METRIC VALUE
John At work IQ 0
John At home EQ 10
John At a concert KQ 0
Jim At work IQ 0
Jim At home KQ 0
Tina At home IQ 100
Tina At work EQ 0
Tina At work KQ 0
In this case, only KQ should be returned since it is always zero for all Names and their instances.
Are you looking for something like this?
SELECT metric
FROM metrics
GROUP BY metric
HAVING SUM(metric_value) = 0
Here is SQLFiddle demo
UPDATE If metric_value can have negative values then use this one
SELECT metric
FROM metrics
GROUP BY metric
HAVING SUM(ABS(metric_value)) = 0
Here is updated SQLFiddle demo
Even though this looks suspiciously like homework.... see if this gives you what you're after:
SELECT DISTINCT M1.Metric
FROM METRICS M1
WHERE NOT EXISTS (
SELECT * FROM METRICS M2
WHERE M2.Metric <> 0
AND M1.Metric = M2.Metric
)
A list based on your data:
SELECT name, metric FROM metrics GROUP BY name, metric HAVING SUM(metric_value) = 0
Most of the other answers assume that metric is positive. The OP says it can be any numeric. Here are two methods for this to work.
Check on the sum of the absolute values:
SELECT metric
FROM metrics
GROUP BY metric
HAVING SUM(abs(metric_value)) = 0
Explicitly check that there are no non-zero values:
SELECT metric
FROM metrics
GROUP BY metric
HAVING SUM(case when metric_value <> 0 and metric_value is not null then 1 else 0 end) = 0
Related
I have to calculate the percentage of total daily users that are x_users. X_users are defined as those in column y with records that isnull or ='null'. Isnull is a null record and 'null' is the string - both are in my tables.
For simplicity, I provided a shortened example (minus all the dimensions and group bys) of my query and subquery below.
Sample query
COUNT (DISTINCT (CASE
WHEN event_name ='launch' THEN user_id
END
)) AS daily_users,
SUM(is_null + null_str) as x_users
Sample subquery
if(column_y is null,1,0) as is_null,
if(column_y = 'null',1,0) as null_str
However, when I run this query, I am resulting in a table where my number of x_users are much higher than the daily user. That is not correct since the type of user (in this case, x_users) should be lower than the total users.
Sample final table
User
country
daily_users
x_users
1
US
5
12
2
UK
10
18
Can anyone help point me in the right direction? Any help is appreciated. Thanks!
I speculate that you want something like this:
COUNT(DISTINCT CASE WHEN event_name = 'launch' THEN user_id END) as daily_users,
COUNT(DISTINCT CASE WHEN event_name = 'launch' AND (is_null > 0 OR null_str > 0) THEN user_id END) as daily_x_users,
I need to replace the value in column imp from 1-0 to 1 and sum it up. Column imp is a STRING, so it also needs to be converted to INT. Each line represents the record so I need to sum up imp and group by another column (in order to get the number of records for a specific Advertiser)
My data looks like this:
advertiser advertiser_id imp
Frank 123 1-0
Frank 123 1-0
Mike 124 1-0
My query:
SELECT
a.AdvertiserID as AdvertiserID,
SUM(
CASE
WHEN a.imp = '1-0' THEN "1"
END
),
b.advertiser_name as AdvertiserName,
FROM
(
`bigquery_table_a` a
INNER JOIN `another_bigquery_table` b ON (a.AdvertiserID = b.advertiser_id)
)
GROUP BY
AdvertiserID,
AdvertiserName
Error message: No matching signature for aggregate function SUM for argument types: STRING
Desired output:
advertiser advertiser_id imp
Frank 123 2
Mike 124 1
Are you just looking for aggregation and count()?
SELECT AdvertiserID, AdvertiserName, COUNT(*)
FROM `bigquery_table_a` a JOIN
`another_bigquery_table` b
ON (a.AdvertiserID = b.advertiser_id
GROUP BY AdvertiserID, AdvertiserName;
Or, if you specifically want to count values of '1-0', use COUNTIF():
SELECT AdvertiserID, AdvertiserName, COUNTIF(imp = '1-0')
FROM `bigquery_table_a` a JOIN
`another_bigquery_table` b
ON (a.AdvertiserID = b.advertiser_id
GROUP BY AdvertiserID, AdvertiserName;
The immediate problem with your code is that as you point out you want an INTEGER type so you can sum it;. Yet your CASE goes out of its way to return a STRING type instead. So you could change
CASE
WHEN a.imp = '1-0' THEN "1"
END
to
CASE
WHEN a.imp = '1-0' THEN 1
END
You might also want to add an ELSE condition, but honestly that isn't likely to matter for your purpose; if you did, it would look like
CASE
WHEN a.imp = '1-0' THEN 1
ELSE 0
END
Now there also may be simpler ways to get the count you want; what else you might do depends what DBMS you're using. But from where you are, the above seems like the simplest fix.
I'm working with a data set that looks similar to the following:
Name Value
Unit 1 0
Unit 1 27
Unit 1 30
Unit 1 10
Unit 1 4
Unit 1 0
Unit 2 0
Unit 2 0
Unit 2 29
Unit 2 0
Unit 3 10
and so on. I would like to create a query that lists the records as follows:
Name ZeroRecords
Unit 1 2
Unit 2 3
Unit 3 0
Where I can list the number of records that are 0. I've tried using a totals row counting Value's, with a criteria of "=0" but it just turns up blank.
I'm sure this is much easier to do with SQL but I am not very familiar.
Any suggestions?
You could consider grouping your records by the Name property along with a COUNT() aggregate to get the count for each group and if you filter it down to only check the Value columns that are zero, you could use :
SELECT Name,
COUNT(*) AS ZeroRecords
FROM YourTable
WHERE Value = 0
GROUP BY Name
You can use conditional aggregation. In MS Access, this looks like:
select name, sum(iif(value = 0, 1, 0)) as numzeros
from t
group by name;
Let's consider this table:
[name] [type]
"Ken Anderson" 1
"John Smith" 2
"Bill Anderson" 1
"George Anderson" 1
"Taylor Smith" 1
"Andrew Anderson" 2
"Dominic Smith" 2
and that query:
SELECT mates.type, COUNT(*) AS SmithsCount
FROM mates
WHERE mates.name LIKE "* Smith"
GROUP BY mates.type
The result should be like
[type] [SmithsCount]
1 1
2 2
What if I want to get also Andersons Count in each group? Like
[type] [SmithsCount] [AndersonsCount]
1 1 3
2 2 1
And, of course, I want this to be most simple as it can be ;) I'm pretty new in SQL, I readed tutorials on W3 Schools and http://www.sql-tutorial.net/ but there are just poorly exampled basics, any "more" complicated queries. Anybody has some useful links? Thanks.
select type,
sum(case when name like '% Smith' then 1 else 0 end) as SmithCount,
sum(case when name like '% Anderson' then 1 else 0 end) as AndersonCount
from mates
group by type
You need a pivot table. This is a feature supported by some RDBMS (Oracle, SQLServer and probably others).
A pivot table let's you use values as columns for aggregations. See my post here: How to transform vertical data into horizontal data with SQL?
The pivot table will alow you to also get the counts of all the other people in your list.
Your query is close, but you must use % instead of * as the wildcard character.
select type,
sum(case when name like '%Smith' then 1 else 0 end) as SmithCount,
sum(case when name like '%Anderson' then 1 else 0 end) as AndersonCount
group by type
In standard SQL parlance this is not supported in the presentation that you propose.
Standard SQL way would be to first normalize data into mates.first_name, mates.last_name and then do:
SELECT mates.type, mates.last_name, COUNT(*) AS last_name_count
FROM mates
WHERE mates.last_name IN ('Smith', 'Anderson')
GROUP BY mates.type, mates.last_name
Which would provide output such as
type last_name last_name_count
1 Anderson 3
1 Smith 1
2 Anderson 1
2 Smith 2
this is the same info that you are looking for, but the format/presentation is not the same.
Historically you were supposed to pivot/crosstab this data in the client application (as part of the presentation layer).
Of course a lot of times it is useful or necessary to do it in SQL layer so extensions to the standard were made, such as pivot (MSSQL) or crosstab (postgres), etc...
I am developing a small stored procedure on SQL server 2008. I have little knowledge on SQL queries, but enough to achieve simple tasks. However I came up with a problem I can't solve myself. Before I start explaining my problem, please pardon me if I spell a SQL query-word wrong because I am not a native English speaker.
I have 4 fields(CSV representation):
ID, NAME, VALUES, ANSWER
25, Tom , 2400 , 0
25, Tom , 600 , 0
25, Tom , 500 , 1
25, Tom , 300 , 1
27, Jerry, 100, 0
27, Jerry, 20, 1
27, Jerry, 60, 1
27, Jerry, 2000, 0
What I want to do is group by the selection by its ID and NAME, Sum up it's values in a field named positive when ANSWER = 1 and negative when ANSWER = 0.
ID, NAME, SUM, NEGATIVE, POSITIVE
25, Tom, 3000, 800
27, Jerry, 2100, 80
I Guess my question has been asked several times, but I wasn't able to find anything about it, probably because I am using the wrong terms. Anyway if someone could help that would save me a lot of time.
You'll do so with a CASE statement.
select Id
, Name
, SUM(case when answer = 1 then Values else 0 end) as Positive
, SUM(case when answer = 0 then Values else 0 end) as Negative
from MyTable
group by Id
, Name
Rewrite your SQL with columns such as this:
sum(case when answer=0 then values else 0 end) negative
Ephismen,
The example you give has a hidden problem in it. Will you always have at least one positive and one negative? What do you want to happen if you only have one or the other and not both. Joining the table to itself will not work when you have multiple rows for each id and name.
A UNION of two separate queries will be able to answer these questions, but not sure if it applies for SQL server 2008.
You may be able to achieve this by using the group by clause for SQL as follows:
select id
, name
, sum (neg_values) as negative
, sum (pos_values) as positive
from -- temporary table
( select id
, name
, sum (values) as neg_values
, 0 as pos_values -- placeholder
from mytable
where answer = 0 -- negative
group by id
, name
union all
select id
, name
, 0 as neg_values -- placeholder
, sum (values) as pos_values
from mytable
where answer = 1 -- positive
group by id
, name
)
group by id
, name
The temporary table (inner select with union) will return rows similar to this:
id name neg_value pos_value
25 tom 3000 0
25 tom 0 800
27 jerry 2100 0
27 jerry 0 80
The final select will return your desired results (summing them together).