DB2 SQL column percentage calculation - sql

Need to calculate a percentage of filled rows in a column(string).
String column could contain zero length strings (should be excluded)
How to re-write this SQL in one sentence (without WITH operator)?
with A(COUNT) // needed rows
as(
select count(FAMILY) from T1
where length(FAMILY)>0
),
B(COUNT) // total rows
as(
select count(*) from T1)
select A.COUNT*100/B.COUNT from A,B

You can use sub-selects instead of WITH; for example:
select
((select count(*) from T1 where length(FAMILY) > 0) * 100) /
(select count(*) from T1)
from sysibm.sysdummy1

Related

Subtraction of two SELECT statements in SQL (redshift)

Can someone explain why the below doesn't work?
((SELECT COUNT(*) FROM Table1) - (SELECT Count(Metric) FROM Table1)) as X
Count(*) will give me all the rows in the table and Count(Metric) will give me the non-null values in the Metric column. So the difference between these will give me the number of null values in the Metric column and I have labelled this column X. I just want the difference between the two in Column X but not sure why it isn't working.
By the way, I know I can get it to work via the below:
SELECT COUNT(*) as a, count(metric) as b, COUNT(*)-COUNT(metric) as c
You would need to select the result:
SELECT ((SELECT COUNT(*) FROM Table1) - (SELECT Count(Metric) FROM Table1)) as X
But it is simpler to use conditional aggregation:
SELECT SUM(CASE WHEN Metrics IS NULL THEN 1 ELSE 0 END) X FROM table1
A SELECT query needs to start with SELECT (or WITH or a parenthesis if the query is a compound query with a set operator such as UNION ALL).
One method is:
SELECT ((SELECT COUNT(*) FROM Table1) - (SELECT Count(Metric) FROM Table1)) as X
A better method is:
SELECT COUNT(*) - Count(Metric) as X
FROM Table1
Not sure about amazon-redshift, but in standard SQL I would just count the records where the field is null instead of counting all minus where they are not null.
SELECT COUNT(*) FROM Table1 WHERE Metric IS NULL;

How to divide two SELECT statements to get a percentage with SQL

I'm trying to calculate the the percentage of items sent by royal mail from the delivery table.
(SELECT post_method
FROM delivery_tbl
WHERE post_method = 'RM')
/
SELECT post_method
FROM delivery_tbl;
I get an error saying
"SQL command not properly ended".
Any help on this would be great! Thanks!
You can do this using conditional aggregation, like so:
SELECT round (100 * (count(case when post_method = 'RM' then 1 end) / count(*)), 2) royal_mail_items_percentage
FROM delivery_tbl;
I've included the round function as it looks like you only want to display up to 2 decimal places.
Doing the query using conditional aggregation means you only have to query the table once, so it should be more performant than the other answers, which need to hit the table more than once.
Select post_method, (Count(post_method)* 100 / (Select Count(*) From
delivery_tbl)) as percentage
From delivery_tbl
Where post_method = 'RM'
Group By post_method
You are doing a division of 2 queries, but to properly display the result, you need to add a SELECT statement of the division.
This is wrong:
-- Result: SQL command not properly ended
(SELECT 100 FROM DUAL) / (SELECT 50 FROM DUAL)
This is OK:
-- Result: 2
SELECT
(SELECT 100 FROM DUAL) / (SELECT 50 FROM DUAL)
FROM
DUAL
You should also try to add column names so it's clearer:
-- ResultOfDivision: 2
SELECT
(SELECT 100 FROM DUAL) / (SELECT 50 FROM DUAL) ResultOfDivision
FROM
DUAL
Please keep in mind that when doing these type of divisions (or any arithmetic operation) between subqueries, each subquery must return 1 row. If they don't then the SQL engine wouldn't know which row to use and throws an error.
-- Result: single-row subquery returns more than one row.
SELECT
(SELECT 100 FROM DUAL) / (SELECT SomeColumn FROM YourTableWithManyRows) ResultOfDivision
FROM
DUAL
For this last example, the correct expression would be the following (for each row).
SELECT
(100 / SomeColumn) ResultOfDivision
FROM
YourTable
WHERE
SomeColumn <> 0 -- Prevent division by 0!!
For your case, seems that you are trying to see the following:
-- Make sure SELECT COUNT(1) FROM delivery_tbl isnt 0!
SELECT
post_method,
COUNT(post_method) * 100 / (SELECT COUNT(1) FROM delivery_tbl) 100perc, -- 100 based percentage
COUNT(post_method) / (SELECT COUNT(1) FROM delivery_tbl) 1perc -- 1 based percentage
FROM
delivery_tbl
GROUP BY
post_method
SELECT ((SELECT post_method FROM delivery_tbl Where post_method = 'RM')/ (SELECT post_method FROM delivery_tbl))*100 as royalperc
Updated query to get counts instead
SELECT ((SELECT COUNT(post_method) FROM delivery_tbl Where post_method = 'RM')/ (SELECT COUNT(post_method) FROM delivery_tbl))*100 as royalperc
I believe you should use the second query
Add a SELECT statement at the beginning:
SELECT ((SELECT post_method FROM delivery_tbl Where post_method = 'RM') / (SELECT post_method FROM delivery_tbl));
Use the sql:
select (
(select sum(post_method) from delivery_tbl where post_method = 'RM') /
(select sum(post_method) from delivery_tbl)) * 100 as "royalperc" from dual ;

Using a value from one query in second query sql

SELECT AS, COUNT(*)
FROM Table1
HAVING COUNT(AS)>1
group BY AS;
This produces the result
AS COUNT
5 2
I then want to use the AS value in another query and only output the end result. Is this possible.i was thinking something like.
SELECT *
FROM
TABLE 2
Where AS =(
SELECT AS, COUNT(*)
FROM Table1
HAVING COUNT(AS)>1
group BY AS;
);
This is called a subquery. To be safe, you would use in instead of = (and as is a bad name for a column, because it is a SQL key word):
SELECT *
FROM TABLE2
WHERE col IN (SELECT col
FROM Table1
GROUP BY col
HAVING COUNT(col) > 1
);
Your first query is also incorrect, because the having clause goes after the group by.
You could use a subquery with the in operator:
SELECT *
FROM table2
WHERE AS IN (SELECT AS
FROM table1
GROUP BY AS
HAVING COUNT(*) > 1)

How can I get the count of multiple columns in SQL

Say I had two tables in SQL. Now I would like to get the quotient of the count of table 1 and count of table 2. How can I do that?
In Short:
(# of rows in table 1) / (# of rows in table 2)
EDIT:
This is what I tried:
SELECT COUNT(t1.a) / COUNT(t2.a)
FROM table1 t1, table2 t2
Here's one way to get the result:
SELECT c1.cnt / c2.cnt AS q
FROM ( SELECT COUNT(1) AS cnt
FROM table1
) c1
CROSS
JOIN ( SELECT COUNT(1) AS cnt
FROM table2
) c2
Another way to get an equivalent result:
SELECT (SELECT COUNT(1) FROM table1) / (SELECT COUNT(1) FROM table2) AS q
I would prefer the first query if I also needed to return the counts from the tables as separate columns in the resultset, for example:
SELECT c1.cnt AS table1_count
, c2.cnt AS table2_count
, c1.cnt / c2.cnt AS q
FROM ...
Try this:
SELECT COUNT(table1.column) as 'Table 1 Count'
,COUNT(table2.column) as 'Table 2 Count'
,COUNT(table1.column) / COUNT(table2.column) as 'Quotient'
FROM table1, table2
with
Ctable1 as
(select count(*) as num1 from table1),
Ctable2 as
(select count(*) as num2 from table2)
select num1 / num2 as quotient
from Ctable1,Ctable2
Remember:
When you count column, rows with "NULL" data will NOT count. (If you use Oracle, you can use count(a.*)
Int division in sql like most languages, returns int. (5/2 = 2 and not 2.5).

Pattern matching SQL on first 5 characters

I'm thinking about a SQL query that returns me all entries from a column whose first 5 characters match. Any ideas?
I'm thinking about entries where ANY first 5 characters match, not specific ones. E.g.
HelloA
HelloB
ThereC
ThereD
Something
would return the first four entries:
HelloA
HelloB
ThereC
ThereD
EDIT: I am using SQL92 so cannot use the left command!
Try this :
SELECT *
FROM YourTable
WHERE LEFT(stringColumn, 5) IN (
SELECT LEFT(stringColumn, 5)
FROM YOURTABLE
GROUP BY LEFT(stringColumn, 5)
HAVING COUNT(*) > 1
)
SQLFIDDLE DEMO
This selects the first 5 characters, groups by them and returns only the ones that happen more than once.
Or with Substring:
SELECT * FROM YourTable
WHERE substring(stringColumn,1,5) IN (
SELECT substring(stringColumn,1,5)
FROM YOURTABLE
GROUP BY substring(stringColumn,1,5)
HAVING COUNT(*) > 1)
;
SQLFIDDLE DEMO
Sounds easy enough...
In SQL Server this would be something along the lines of
where Left(ColumnName,5) = '12345'
Try
Select *
From tbl t1
Where exists (
Select 1
From tbl t2
Where left(t1.str, 5) = left(t2.str)
Group by left(t2.str, 5)
Having count(1) > 1
)
You didn't specify your DBMS. If it supports Windowed Aggregate functions it's:
select *
from
(
select
tab.*,
count(*) over (partition by substring(col from 1 for 5) as cnt
from tab
) as dt
where cnt > 1
You want to work with a CTE approach.
Something like this:
with CountriesCTE(Id, Name)
as (
select Id, Name from Countries
)
select distinct Countries.Name
from CountriesCTE, Countries
where left(CountriesCTE.Name,5) = left(Countries.Name,5) and CountriesCTE.Id <> Countries.Id