i'm searching for an SQL request which gives me all columns in a table that are never populated.
For example, in a table like this one :
column 1 | column 2 | column 3 | column 4 | column 5
---------+----------+----------+----------+---------
value | NULL | value | value | NULL
NULL | NULL | value | value | NULL
value | NULL | value | NULL | NULL
value | NULL | value | value | NULL
The request will return : column 2, column 5
EDIT :
I've created this little PHP script to generate the query and print the result :
$columns = $sql->select("SELECT column_name FROM information_schema.COLUMNS WHERE TABLE_NAME='table_name'");
$query = "SELECT ";
foreach($columns as $column) {
$query .= "case when count(".$column[0].") = 0 then '".$column[0]."' end, ";
}
$query = substr($query, 0,-2);
$query .= " FROM table_name";
var_dump($sql->select($query));
Something like:
select case when count(column1) = 0 then 'column 1' end,
case when count(column2) = 0 then 'column 2' end,
case when count(column3) = 0 then 'column 3' end,
case when count(column4) = 0 then 'column 4' end,
case when count(column5) = 0 then 'column 5' end
from tablename
I.e. count all values for a column, if 0 found return column name.
You can determine if a column contains no values by doing:
select 'column2'
from table t
having max(column2) is null;
You can repeat this for all columns using union all:
select 'column1'
from table t
having max(column1) is null
union all
select 'column2'
from table t
having max(column2) is null
. . .
This returns the results on multiple rows.
If you want a single row:
select concat_ws(', ',
(case when max(column1) is null then 'column1' end),
(case when max(column2) is null then 'column2' end),
(case when max(column3) is null then 'column3' end),
(case when max(column4) is null then 'column4' end),
(case when max(column5) is null then 'column5' end)
)
from table t;
Related
Table: tbl_1
Columns: name, option
-> name | option
-> abc_1 | yes
-> abc_2 | no
-> abc_3 | yes
-> abc_1 | no
-> abc_2 | yes
-> abc_3 | no
-> abc_1 | yes
-> abc_2 | no
-> abc_3 | yes
-> abc_1 | yes
-> abc_2 | no
-> abc_3 | yes
Now, The query I want to ask that ......
How can I get those unique names which are have options:yes more than no ?
The query should return
-> name
-> abc_1
-> abc_3
I tried lots of queries but did not succeed, Kindly help
Thanks.
MySql evaluates Boolean expressions as 0 or 1 for False and True, so there is no need for IF or CASE statements:
select name
from tbl_1
group by name
having sum(`option` = 'yes') > sum(`option` = 'no')
See the demo.
Results:
| name |
| ----- |
| abc_1 |
| abc_3 |
A terse MySQL query to return the specfied result would be something like:
SELECT t.name
FROM tbl_1 t
GROUP
BY t.name
HAVING SUM(IF(t.option = 'yes',1,0)) > SUM(IF(t.option = 'no',1,0))
This is using some "conditional aggregation" shorthand.
Let's unpack that a bit, so we can get an understanding of what this query is doing. Consider this query:
SELECT t.name
, t.option
, IF(t.option = 'yes',1,0) AS option_yes
, IF(t.option = 'no' ,1,0) AS option_no
FROM tbl_1 t
ORDER
BY t.name
The expressions in the SELECT list are evaluated for each row, the IF() function evaluates to either a 1 or a 0.
And now consider what happens when do aggregation of those expressions, adding up all of the 1s and 0s
SELECT t.name
, t.option
, SUM( IF(t.option = 'yes',1,0) ) AS cnt_option_yes
, SUM( IF(t.option = 'no' ,1,0) ) AS cnt_option_no
FROM tbl_1 t
GROUP
BY t.name
, t.option
Now leave "option" out of the group by clause, and do a comparison of the two aggregates.
SELECT t.name
, SUM( IF(t.option = 'yes',1,0) ) AS cnt_option_yes
, SUM( IF(t.option = 'no' ,1,0) ) AS cnt_option_no
, SUM(IF(t.option='yes',1,0) ) > SUM(IF(t.option='no',1,0)) AS _compare
FROM tbl_1 t
GROUP
BY t.name
It's possible to do a comparison of the aggregates in a HAVING clause. And that yields the query at the very beginning of this answer.
You could try a conditional sum
select name
, sum( case when `option` ='yes' then 1 else 0 end) num_yes
, sum( case when `option` ='no' then 1 else 0 end) num_no
from my_table
group by name
order by num_yes desc, num_no desc
Conditional aggregation -
select
name,
count (case when `option` = 'yes' then 1 else null end) as y,
count (case when `option` <> 'yes' then 1 else null end) as n
from
tbl_1
group by
`name`
having count (case when `option` = 'yes' then 1 else null end) > count (case when `option` <> 'yes' then 1 else null end)
Fiddle
I have a table that I want to count number of fields which their field is not null. How I can return the result?
SELECT * FROM `fakelos2` WHERE fields are not Null
Instead of are use is, while to count rows for particular field, you use count function like below:
SELECT count(*)
FROM fakelos2
WHERE fields is not null
Now you have to count each and every field then you have to use case when then like below:
SELECT
((CASE WHEN field1 IS NULL THEN 1 ELSE 0 END)
+ (CASE WHEN field2 IS NULL THEN 1 ELSE 0 END)
+ (CASE WHEN field3 IS NULL THEN 1 ELSE 0 END)
...
...
+ (CASE WHEN field10 IS NULL THEN 1 ELSE 0 END)) AS sum_of_nulls
FROM fakelos2
While I was preparing an answer to one of our fellows here on SO I've encounter an odd situation, at least to me. The original question is here: Pivot Table Omitting Rows that Have Null values
I've modified the query to use max instead of group_concat in order to show the "problem" in all databases.
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
The result of this query is this:
ID FN LN JT
1 Sampo Kallinen Office Manager
2 Jakko Salovaara Vice President
3 (null) Foo No First Name
The user asks to filter the row with id 3 because the field value is null.
When it seems pretty obvious that only it needs to do was to add a WHERE value IS NOT NULL constraint on that query to achieve what the user expect. It won't work.
So I start to test it on the other databases to see what happens (Queries with the WHERE CLAUSE)
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
WHERE value is not null
GROUP BY id
Mysql: http://sqlfiddle.com/#!2/78395/1
Postgres: http://sqlfiddle.com/#!15/78395/1
SQLServer: http://sqlfiddle.com/#!6/78395/1
Oracle: http://sqlfiddle.com/#!4/78395/1
For my surprise the result was the same, none worked.
Then I tried a different version of the same query:
SELECT * FROM (
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
) T
WHERE fn IS NOT NULL
AND ln IS NOT NULL
AND jt IS NOT NULL
Oracle: http://sqlfiddle.com/#!4/78395/2 WORKED
MySql: http://sqlfiddle.com/#!2/78395/2
Postgres: http://sqlfiddle.com/#!15/78395/2
SQLServer: http://sqlfiddle.com/#!6/78395/2
The only way I could make it work on all databases was with this query:
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
WHERE NOT EXISTS (SELECT * FROM tbl b WHERE tbl.id=b.id AND value IS NULL)
GROUP BY id
So I ask:
What is happening here that except for that specific case on Oracle all other DBs seem to ignore the IS NOT NULL filter?
To omit the row from the result if any of the source rows for the same id has value IS NULL, a solution in Postgres would be to use the aggregate function every() or (synonym for historical reasons) bool_and() in the HAVING clause:
SELECT id
, max(case when colID = 1 then value else '' end) AS fn
, max(case when colID = 2 then value else '' end) AS ln
, max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
HAVING every(value IS NOT NULL);
SQL Fiddle.
Explain
Your attempt with a WHERE clause would just eliminate one source row for id = 3 in your example (the one with colID = 1), leaving two more for the same id. So we still get a row for id = 3 in the result after aggregating.
But since we have no row with colID = 1, we get an empty string (note: not a NULL value!) for fn in the result for id = 3.
A faster solution in Postgres would be to use crosstab(). Details:
PostgreSQL Crosstab Query
Other RDBMS
While EVERY is defined in the SQL:2008 standard, many RDBMS do not support it, presumably because some of them have shady implementations of the boolean type. (Not dropping any names like "MySQL" or "Oracle" ...). You can probably substitute everywhere (including Postgres) with:
SELECT id
, max(case when colID = 1 then value else '' end) AS fn
, max(case when colID = 2 then value else '' end) AS ln
, max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
HAVING count(*) = count(value);
Because count() doesn't count NULL values. In MySQL there is also bit_and().
More under this related question:
Is there any equivalent to Postgresql EVERY aggregate function on other RDBMS?
It works in Oracle because Oracle handles NULL incorrectly in that NULL and '' are the same. The other databases don't do this because it is wrong. NULL is unknown, versus '' which is just a blank, empty string.
So if your where clause said something like WHERE (fn IS NOT NULL or fn <> '') you would probably get further.
I think this is a case where a HAVING clause will do what you need.
SELECT id, max ... (same stuff as before)
FROM tbl
GROUP by id
HAVING fn IS NOT NULL
AND ln IS NOT NULL
AND jt IS NOT NULL
Looking for the way to change row to column. (The comflag is of type bit and not null). Help appreciated
Table1
Id Commflag value
122 0 Ce
125 1 Cf
122 0 Cg
125 1 cs
Here is what I want in result
id ce cf cg cs cp
122 0 null 0 null null
125 null 1 null 1 null
The below query shows error-
SELECT ID , [CE],[CF],[CG],[CS],[CP]
FROM TABLE1
PIVOT ((convert((Commflag)as varchar()) FOR value IN [CE],[CF],[CG],[CS],[CP] as pvt
ORDER BY date
This query does what you want:
select Id, pvt.Ce, pvt.Cf, pvt.CG, pvt.Cs, pvt.Cp
from
(
select Id, cast(Commflag as tinyint) Commflag, value
from Table1
) t
pivot (max(Commflag) for value in ([Ce],[Cf],[CG],[Cs],[Cp])) pvt
SQL Fiddle
Here's another way to do it, without using PIVOT:
select Id,
max(case value when 'Ce' then CAST(Commflag as tinyint) else null end) Ce,
max(case value when 'Cf' then CAST(Commflag as tinyint) else null end) Cf,
max(case value when 'Cg' then CAST(Commflag as tinyint) else null end) Cg,
max(case value when 'Cs' then CAST(Commflag as tinyint) else null end) Cs,
max(case value when 'Cp' then CAST(Commflag as tinyint) else null end) Cp
from Table1
group by Id
order by Id
SQL Fiddle
There is one table which is having only one row with 4 date columns ,initially all date value are null so
if Exists(select 1 from rep_master where pacdt_1=null OR
pacdt_2=null OR
pacdt_3=null OR
pacdt_4=null)
select 0
else
select 1
this one is returning 1
if Exists(select 1 from rep_master where ISNULL(pacdt_1,0)=0 or
ISNULL(pacdt_2,0)=0 or
ISNULL(pacdt_3,0)=0 or
ISNULL(pacdt_4,0)=0 )
select 0
else
select 1
this one is returning 0 ,which is correct result
I m unable to figure out what is wrong with first query?
use IS NULL rather than = NULL
so:
if Exists(select 1 from rep_master
where pacdt_1 is null OR pacdt_2 is null OR
pacdt_3 is null OR pacdt_4 is null)
select 0
else
select 1
You can't equal null, you have to use IS
if Exists(select 1 from rep_master where pacdt_1 IS null OR
pacdt_2 IS NULL OR
pacdt_3 IS NULL OR
pacdt_4 IS NULL)
select 0
else
select 1
to get where the value is not null you use IS NOT
if Exists(select 1 from rep_master where pacdt_1 IS NOT null OR
pacdt_2 IS NOT NULL OR
pacdt_3 IS NOT NULL OR
pacdt_4 IS NOT NULL)
select 0
else
select 1