Mysql create table with sums of nulls and not nulls - mysql

Scenario: I am trying to create an output matrix where I have all the columns names (fields) of a source table in the first column, followed by the sum of all Null values of that original field column.
Ex:
Original Table:
Id1 Code Range
aa 33 null
ab 12 001
ac 53 001
ad null null
null 36 002
Wanted output:
Fields #ofnull #ofnonnull
Id1 1 4
Code 1 4
Range 2 3
For this I have a code that retrieves the names and positions of all the columns in the original matrix, and a snippet which counts my nulls/nonnulls.
Issue: I have no idea how to string those together and get this output with a single query. I tried searching around, but most answers were regarding just counting the nulls, not on the process on inputting a list of columns to the query.
Question: Is it possible to do this? or do I have to feed the query each column name manually?
Code so far:
select
`ordinal_position`,
`column_name`,
from `dev1`.`info`
where `table_schema` = 'dev1'
and `table_name` = 'data1'
order by `ordinal_position`;
select
count(1)
from `dev1`.`data1`
where Id1 is null;
-- where Id1 is not null;

One approach uses a series of unions:
SELECT
'Id1' AS Fields,
COUNT(CASE WHEN Id1 IS NULL THEN 1 END) AS NoNull,
COUNT(Id1) AS NoNonNull
FROM yourTable
UNION ALL
SELECT 'Code', COUNT(CASE WHEN Code IS NULL THEN 1 END), COUNT(Code)
FROM yourTable
UNION ALL
SELECT 'Range', COUNT(CASE WHEN `Range` IS NULL THEN 1 END), COUNT(`Range`)
FROM yourTable;
Demo

You can try using UNION ALL
SELECT
field,
COUNT(CASE WHEN val IS NULL THEN 1 END) AS `#ofnull`,
COUNT(CASE WHEN val IS NOT NULL THEN 1 END) AS `#ofnotnull`
FROM
(
SELECT 'Id1' AS field, Id1 AS val FROM yourTable
UNION ALL
SELECT 'Code', Code FROM yourTable
UNION ALL
SELECT 'Range', `Range` FROM yourTable
) a
GROUP BY field;

Related

SELECT Row if it has same 2 Fields in 1 table. Else, Select null field instead

Would like to select a row if a LOOKUP = COSTID. Else, get the row with the null field instead. Please see table below:
(PAYCODE must be unique)
PAYCODE
LOOKUP
COSTID
ACCOUNT
201
null
null
720001
201
659057
659057
999999
202
null
null
720002
202
659058
659057
999999
null LOOKUP will be selected for PAYCODE 202 because LOOKUP != COSTID as shown above.
The output must be:
PAYCODE
LOOKUP
COSTID
ACCOUNT
201
659057
659057
999999
202
null
null
720002
My SQL so far:
SELECT
*
FROM
gl_table_db t1
WHERE
LOOKUP = COSTID OR LOOKUP IS NULL AND NOT EXISTS(SELECT * FROM gl_table_db t2 WHERE t1.LOOKUP = t2.LOOKUP AND t2.LOOKUP IS NOT NULL
AND t1.LOOKUP IS NOT NULL)
I feel like this is very close but cannot quite get it. Thank you
Here is a ROW_NUMBER based approach. We can assign a label of 1 for those records having the same values for LOOKUP and COSTID. A value of 0 can be assigned where either LOOKUP or COSTID be null, and -1 assigned to all other possibilities. Then, we can retain, for each PAYCODE, the record with the highest priority label value.
WITH cte AS (
SELECT *, CASE WHEN LOOKUP = COSTID THEN 1
WHEN LOOKUP IS NULL OR COSTID IS NULL THEN 0
ELSE -1 END AS label
FROM gl_table_db
),
cte2 AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY PAYCODE ORDER BY label DESC) rn
FROM cte
)
SELECT PAYCODE, LOOKUP, COSTID, ACCOUNT
FROM cte2
WHERE rn = 1;
You were close (beware of parenthesis when mixing ANDs and ORs):
SELECT
*
FROM
gl_table_db t1
WHERE
-- Either we have the not-null version
t1.LOOKUP = COSTID
OR
-- OR - if we don't- have the null version
(t1.LOOKUP IS NULL
AND NOT EXISTS ( SELECT *
FROM gl_table_db t2
WHERE t1.PAYCODE = t2.PAYCODE
AND t2.LOOKUP=t1.COST_ID
)
)

How to simulate a N-dimension INTERSECT with generic SQL

Here is an example of 2 extract from the same table:
SELECT source_id
FROM table_cust_string_value
WHERE cust_string_id=2 AND VALUE LIKE '%TATA%';
SELECT source_id
FROM table_cust_string_value
WHERE cust_string_id=4 AND VALUE LIKE '%TUTU%';
They give 2 sets of source_id.
Right. Now if I need an intersect of those with MySQL (where INTERSECT does not exist) I found this way:
SELECT DISTINCT source_id
FROM (
SELECT source_id
FROM table_cust_string_value
WHERE cust_string_id=2 AND VALUE LIKE '%TATA%'
) t1
INNER JOIN (
SELECT source_id
FROM table_cust_string_value
WHERE cust_string_id=4 AND VALUE LIKE '%TUTU%'
) t2
USING (source_id);
but what if I need to do this from N sets ?
I can't find a solution + I'm worried about the perf. of doing it this way
You can use a grouping approach. Depending on what indexes you have available this might work out better.
SELECT source_id
FROM table_cust_string_value
WHERE cust_string_id IN ( 2, 4 )
GROUP BY source_id
HAVING MAX(CASE WHEN cust_string_id = 2 AND VALUE LIKE '%TATA%' THEN 1 END) = 1
AND MAX(CASE WHEN cust_string_id = 4 AND VALUE LIKE '%TUTU%' THEN 1 END) = 1

How to do SELECT in a column with different parameter and aliases?

I'd like to create a report from this table. I need to get the data from different parameter in a same column.
ID_NUMBER ID_DOCUMENT DOCUMENT_NAME
A001 1 DOC_A_1
A001 2 DOC_A_2
A001 3 DOC_A_3
B001 1 DOC_B_1
B001 3 DOC_B_3
The SELECT parameter are 1 and 2
Then, the SELECT output should be:
ID_NUMBER DOCUMENT_1 DOCUMENT_2
A001 DOC_A_1 DOC_A_2
B001 DOC_B_1 NULL
my current query:
SELECT
tdoc_1.ID_NUMBER,
tdoc_1.DOCUMENT_NAME AS "DOCUMENT_1"
FROM `document` 'tdoc_1'
LEFT OUTER JOIN (
SELECT
tdoc_1.ID_NUMBER,
tdoc_2.DOCUMENT_NAME AS "DOCUMENT_2"
FROM `document` 'tdoc_2'
WHERE `ID_DOCUMENT` = '2'
) temp_doc ON tdoc_1.ID_NUMBER = temp_doc.ID_NUMBER
WHERE ID_NUMBER = 1
The data in the column is big, so, it's better to have a speedy query
You just need some aggregation with pivoting logic here:
SELECT
ID_NUMBER,
MAX(CASE WHEN ID_DOCUMENT = 1 THEN DOCUMENT_NAME END) AS DOCUMENT_1,
MAX(CASE WHEN ID_DOCUMENT = 2 THEN DOCUMENT_NAME END) AS DOCUMENT_2
FROM document
GROUP BY
ID_DOCUMENT
ORDER BY
ID_DOCUMENT;
If you want the document columns to be flexible, then you'll need a bit of dynamic SQL for that. It can't be hard coded.
If you can live with the data in one column, then GROUP_CONCAT() might do what you want:
select id_number,
group_concat(document_name order by id_document) as documents
from document
group by id_number;
The advantage to this approach is that you can use a where clause to select the specific documents you want. For your specific question (for 1 and 2):
select id_number,
group_concat(document_name order by id_document) as documents
from document
where id_document in (1, 2)
group by id_number;

Dynamically creating columns from row data using Select in Bigquery

Background
I want to rename my case statement in sql select statement dynamically.
Eg:
SELECT (case when id= x.id then x.sums end) x.id
as (select id,count(*) sums from table
group by id) x
what i want the output is list of columns created ,with Labels as distinct id's from "id" column.
However,this variable x.id is not dynamically outputing values,rather i get output a single column x.id.
Eg:
Columns in table...
id---c1----c2
1----x1---x2
2----x2----x3
3----x4----x5
columns expected after running query...
1-----2----3
but actual o/p column is::
x.id
Query
Any ideas,how to generate columns dynamically using select query,please correct me ,if i am wrong.
Below is for BigQuery!
Please note: your expectations about output column names are not correct!
Column name cannot start with digit - so in below example - i will be using id_1, id_2 and id_3 instead of 1, 2 and 3
SELECT
SUM(CASE WHEN id = 1 THEN 1 END) AS id_1,
SUM(CASE WHEN id = 2 THEN 1 END) AS id_2,
SUM(CASE WHEN id = 3 THEN 1 END) AS id_3
FROM YourTable
Above example assumes you know in advance your IDs and there are very few of them so it is not a big deal to write manually few numbers of lines with SUM(...) for each id
If this is not a case - you can first generate above query programmatically by running below query
SELECT 'SELECT ' +
GROUP_CONCAT_UNQUOTED(
'SUM(CASE WHEN id = ' + STRING(id) + ' THEN 1 END) AS id_' + STRING(id)
)
+ ' FROM YourTable'
FROM (
SELECT id FROM (
SELECT * FROM YourTable GROUP BY id ORDER BY id
)
as a result - you will get string like below
SELECT SUM(CASE WHEN id = 1 THEN 1 END) AS id_1,SUM(CASE WHEN id = 2 THEN 1 END) AS id_2,SUM(CASE WHEN id = 3 THEN 1 END) AS id_3 FROM YourTable
So, now just copy it and paste into Query Editor and run it
you can see similar example here - https://stackoverflow.com/a/36623258/5221944

Count returned by a Query when Particular column is null and not-null in MySql

i want to select a count returned by a query when a particular column is null and another query to select a count when that column is not null into single query how can i achieve it..?
i had tried some of the example that are avail in SOF but no use..
for example i want to
select students count of class table where the address null and notnull
In MySQL this can do it
SELECT
SUM(IF(address IS NULL,1,0)) as `Student_With_No_Address`,
SUM(IF(address IS NOT NULL,1,0)) as `Student_With_Address`
FROM students
SQL Fiddle Demo
Output :
Student_With_No_Address | Student_With_Address
---------------------------------------------
4 | 6
Try this
SELECT
COUNT(CASE when address is null then 1 end) AS StudentsWithNoAddress,
COUNT(CASE when address is not null then 1 end) AS StudentsWithAddress
FROM Class
You have to write two SELECT statements and combine them using UNION
SELECT 'No Address' AS AddressStatus, COUNT(*) AS NoOfStudents
FROM Class WHERE Address IS NULL
UNION
SELECT 'With Address' AS AddressStatus, COUNT(*) AS NoOfStudents
FROM Class WHERE Address IS NOT NULL
select
SUM( CASE when studentId is not NULL THEN 1 else 0 END ) as result1 ,
SUM( CASE when studentId is NULL THEN 1 else 0 END) as result2
from class