SQL check if group contains NULL - sql

Is there any function to check if a column in a group contains a NULL, alternatively how would I solve this? Example below of data structure.
id | value
----------
1 | NULL
1 | 56
2 | 98
2 | 14
Result:
id | value
----------
1 | 1
2 | 0

try
select id,
count(*) - count(value) as null_value_count
from your_table
group by id
SQLFiddle demo

Another possibility which doesn't use the fact that count(value) ignores NULL values:
select id,
sum(case when value is null then 1 else 0 end) as null_count
from your_table
group by id;

Related

Oracle SQL: Dividing Counts into unique and non unique columns

I have a table that looks like this:
|FileID| File Info |
| ---- | ------------ |
| 1 | X |
| 1 | Y |
| 2 | Y |
| 2 | Z |
| 2 | A |
I want to aggregate by FileID and split the File Info column into 2 separate count columns. I want 1 column to have the count of the Unique File Info and the other to be a count of non-Unique file info.
The result would ideally look like this:
|FileID| Count(Unique)| Count(Non-unique) |
| ---- | ------------ | ----------------- |
| 1 | 1 | 1 |
| 2 | 2 | 1 |
where the non-unique count is the 'Y' and the unique count is from the 'X' and 'Z, A' for FileID 1 and 2 respectively.
I'm looking for ways to gauge uniqueness between files rather than within.
Use COUNT() window function in every row to check if FileInfo is unique and then use conditional aggregation to get the results that you want:
SELECT FileID,
COUNT(CASE WHEN counter = 1 THEN 1 END) count_unique,
COUNT(CASE WHEN counter > 1 THEN 1 END) count_non_unique
FROM (
SELECT t.*, COUNT(*) OVER (PARTITION BY t.FileInfo) counter
FROM tablename t
) t
GROUP BY FileID;
See the demo.
First you select the "Non Unique" rows from the table
SELECT FileInfo
FROM sometableyoudidnotname
GROUP BY FileInfo
HAVING COUNT(*) > 1
Now that you know which ones are unique and non unique you can left join to that table to get the "status" and count it up.
SELECT base.FileID,
SUM(CASE WHEN u.FileID is NOT NULL THEN 1 ELSE 0 END) as nonunique,
SUM(CASE WHEN u.FileID is NULL THEN 1 ELSE 0 END) as unique
FROM sometableyoudidnotname base
LEFT JOIN (
SELECT FileInfo
FROM sometableyoudidnotname
GROUP BY FileInfo
HAVING COUNT(*) > 1
) u ON base.FileInfo = u.FileInfo
GROUP BY base.FileID
Have a derived table that counts occurrences of each fileid. JOIN and GROUP BY:
select t1.FileID,
sum(case when t2.ficount = 1 then 1 else 0 end),
sum(case when t2.ficount > 1 then 1 else 0 end)
from tablename t1
join
(
select fileinfo, count(*) ficount
from tablename
group by fileinfo
) t2
on t1.fileinfo = t2.fileinfo
group by t1.FileID

SQL Server - group by ID if column contains a value

I have following table:
ID | NR | Status
1000 | 1 | A
1000 | 2 | A
1001 | 3 | A
1002 | 4 | A
1002 | 5 | N
1003 | 6 | N
I need to an output which groups these by ID's. The NR column can be ignored. If one of the records with those ID's contains Status A, That status will be given as result.
So my output would be:
ID | Status
1000 | A
1001 | A
1002 | A
1003 | N
Any suggestions/ideas?
Although min() is the simplest method, it is not easily generalizable. Another method is:
select id
(case when sum(case when status = 'A' then 1 else 0 end) > 0
then 'A'
else 'N' -- or whatever
end) as status
from t
group by id;
Or, if you have a table with one row per id, then I would use exists:
select ids.id,
(case when exists (select 1 from t where t.id = ids.id and t.status = 'A')
then 'A' else 'N'
end) as status
from ids;
This saves on the group by aggregation and can use an index on (id, status) for optimal performance.
Do a GROUP BY, use MIN() to pick minimum status value for each id, and A < N!
select id, min(status)
from tablename
group by id
You want exactly the records that match the predicate "If one of the records with those ID's contains Status A, that status will be given as result." ?
The query can be written simply as:
Select distinct ID, STATUS from [your working TABLE] where STATUS = 'A'.
Hope this can help.

Can row_number() ignore null in oracle

I have data like this
---------------------------
| code | other column
---------------------------
| C | a
| null | a
| A | a
| null | a
| null | a
----------------------------
How can i write query to get row_number without counting null column.
----------------------------------
| id | code | other column |
----------------------------------
| 1 | C | a
| | null | a
| 2 | A | a
| | null | a
| | null | a
----------------------------------
Well, not specifically. But you can get what you want by using conditional logic:
select (case when code is not null
then row_number() over (partition by (case when code is not null then 1 else 0 end)
order by . . .
)
end) as id
It is not clear to me what the order by is for the row_number() which is what the . . . means.
If you need to order on code (descendent in your example) with NULLs last:
select
decode(code,null,null,row_number() over (order by code DESC NULLS LAST)) rn,
code
from test;
If you need to order on OTHER column:
select
decode(code,null,null,row_number() over (order by decode(code,null,null,'x') NULLS LAST, other DESC)) rn,
code, other
from test;
You can use row_number on the desired subset and then union all the other records:
select row_number() over (order by sortkey) as id, code, other_column
from mytable
where code is not null
union all
select null as id, code, other_column
from mytable
where code is null
order by sortkey;
Another easy way would be:
Select
CASE WHEN code IS NOT NULL THEN ROW_NUMBER() OVER (PARTITION BY code order by code)
ELSE NULL END id,
code,
other_column
FROM table;
Example, in my case using IS NOT NULL did not work for me, I had to change it to an expression:
SELECT A.ITEMNAME,
CASE
WHEN (SELECT T1.MAXSTOCK
FROM DATOS T1
WHERE T1.MAXSTOCK) > 5 THEN
ROW_NUMBER() OVER(PARTITION BY CASE
WHEN (SELECT T1.MAXSTOCK
FROM DATOS T1
WHERE T1.MAXSTOCK) <= 5 /*here should go IS NOT NULL*/
THEN
1
END ORDER BY A.ITEMNAME)
ELSE
NULL
END AS #ROW
FROM TABLE A

SQL query design for getting a table with column depending on a column value in SQL Server

I would like to do a SQL query in SQL Server to get a table:
Table1:
id t value
1 R 2412
1 Q 98797
2 R 132
2 Q 7589
I need to get table:
id R_value Q_value
1 2412 98797
2 132 7589
I used case and when, but I got
id R_value Q_value
1 2412 null
1 null 98797
Any help would be appreciated.
Use conditional aggregation:
SQL Fiddle
SELECT
id,
MAX(CASE WHEN t = 'R' THEN value END) AS R_value,
MAX(CASE WHEN t = 'Q' THEN value END) AS Q_value
FROM YourTable
GROUP BY id
You can use max or min with the group by to get rid of null values and aggregate rows with the same id:
select id
, min(case when t = 'R' then value end) as R_value
, min(case when t = 'Q' then value end) as Q_value
from tbl
group by id
You can easily use the PIVOT table operator like this:
SELECT
id,
R AS R_value,
Q AS Q_value
FROM table1 AS t1
PIVOT
(
MAX(value)
FOR t IN(R, Q)
) AS p;
SQL Fiddle Demo
This will give you:
| id | R_value | Q_value |
|----|---------|---------|
| 1 | 2412 | 98797 |
| 2 | 132 | 7589 |

Mysql query for better sorting of result

The mysql table that I'm using has a structure:
id | type | date
--------------------------------
101 | 1 | 2011-02-08
102 | 2 | 2011-02-08
103 | 2 | 2011-02-08
104 | 2 | 2011-02-07
105 | 1 | 2011-02-07
105 | 1 | 2011-02-07
What I want to do is create a query that will give the following result:
total type 1 | total type 2 | date
------------------------------------------------
1 | 2 | 2011-02-08
2 | 1 | 2011-02-07
I tried with following query but not getting the desired result
SELECT count(DISTINCT id) as total, date, type FROM my_table WHERE type !='0' GROUP BY date, type ORDER BY date DESC
How can I do that?
Thanks for all suggestions
Use:
SELECT t.date,
SUM(CASE WHEN t.type = 1 THEN 1 ELSE 0 END) AS total_type_1,
SUM(CASE WHEN t.type = 2 THEN 1 ELSE 0 END) AS total_type_2
FROM YOUR_TABLE t
WHERE t.type != 0
GROUP BY t.date
ORDER BY t.date DESC
I'm assuming the type column is numeric, not string based like the single quotes suggest. Change to suit if that's not the case.
Try this:
SELECT type, COUNT(*) as total_type, date FROM my_table WHERE type != '0' GROUP BY type ORDER BY date DESC
What you're asking for is pivot functionality, which I guess mysql isn't great at.
If it works for you, I'd suggest altering the output to:
type count date
==== ===== ====
1 1 2011-02-08
....
and rearrange at application logic. It would probably also make your SQL more db-independent.