Array contains NULL value - sql

I'm trying to select the last enddate per nr. In case the nr contains an enddate with value NULL, it means this nr is still active. In short I cannot use MAX(enddate) because out of 2013-09-25 and NULL it would select the date whereas I need NULL.
I tried the following query though it seems that NULL IN (enddate) does not return what I suspected. Namely: 'if the array contains at least one value NULL...'. In other words, NULL should overrank MAX().
SELECT nr,
CASE WHEN NULL IN (enddate) THEN NULL ELSE MAX(enddate) END
FROM myTable
GROUP BY nr
Does someone know how to replace this expression?

You can use the query below. It returns NULL before other dates (provided that you put a date great enough) and then restores NULL.
SELECT nr, CASE d WHEN '20990101' THEN NULL ELSE d END d
FROM (
SELECT nr,
CASE MAX(ISNULL(enddate, '20990101') d
FROM myTable
GROUP BY nr
)
I couldn't check the syntax so there may be small typos.

You could use this query. The CTE calculates the maximum date ignoring any nulls, this is then left joined back to the table to see if there is a null value for each nr value. The case statement returns a null if it exists or the maximum date from the CTE.
WITH CTE1 AS
(SELECT nr, MAX(enddate) MaxEnddate
FROM myTable
GROUP BY nr)
SELECT CTE1.nr,
CASE WHEN MyTable.enddate IS NULL AND MyTable.NR IS NOT NULL THEN NULL ELSE CTE1.MaxEndDate END AS EndDate
FROM CTE1
LEFT JOIN MyTable
ON MyTable.nr=CTE1.nr
AND MyTable.enddate IS NULL

Just to build off of #Szymon answer a little bit:
drop table #temp
create table #temp (MyDate date) insert into #temp (MyDate) values ('1/1/2010'),('1/1/2011'),('1/1/2012'),(NULL)
select * from #temp
SELECT
(CASE WHEN MAX(ISNULL(MyDate, '2099-01-01')) = '2099-01-01' THEN NULL ELSE MAX(ISNULL(MyDate, '2099-01-01')) END) as Max_Date
FROM
#temp
The query replaces a NULL value with '2099-01-01'. Then, it looks to see if the Max is equal to '2099-01-01' and if so, returns NULL, and otherwise returns the actual Max.

Related

How to do calculations and then compare them in SQL Server

I have a table with columns Recordnumber, Test, Value, Date and Complement. Recordnumber and test are the primary key.
I need compare values from TW01SS and TW01D1+TW01D2 with the same Recordnumber and depending on which value is bigger add it to Complement column. Any ideas?
Thank you
You can create two CTE's, one to get the SS count and the other the D1+D2 count then UPDATE the Complement column by the Recordnumber.
See WITH common_table_expression (Transact-SQL)
Specifies a temporary named result set, known as a common table
expression (CTE). This is derived from a simple query and defined
within the execution scope of a single SELECT, INSERT, UPDATE, DELETE
or MERGE statement. This clause can also be used in a CREATE VIEW
statement as part of its defining SELECT statement. A common table
expression can include references to itself. This is referred to as a
recursive common table expression.
;WITH
D1D2_Count
AS
-- Define D1+D2 Count CTE Query.
(
SELECT RecordNumber AS D1D2_ID,
SUM(Value) OVER(PARTITION BY RecordNumber) AS D1D2_Total
FROM TestA
WHERE Test LIKE '%D1' OR Test LIKE '%D2'
),
SS_Count
AS
-- Define SS Count CTE Query.
(
SELECT RecordNumber AS SS_ID,
SUM(Value) OVER(PARTITION BY RecordNumber) AS SS_Total
FROM TestA
WHERE Test LIKE '%SS'
)
UPDATE A
SET Complement =
CASE WHEN D1D2_Total > SS_Total
THEN D1D2_Total
ELSE SS_Total
END
FROM TestA AS A
LEFT JOIN D1D2_Count ON RecordNumber = D1D2_ID
LEFT JOIN SS_Count ON RecordNumber = SS_ID
See Fiddle.
Optionally, you can add a WHERE clause to the end of the UPDATE statement so that it'll only update the Complement that has the greater total
If D1+D2 > SS, UPDATE Only the D1+D2 rows
Otherwise, UPDATE Only the SS rows.
Like this:
WHERE Test LIKE
CASE WHEN D1D2_Total > SS_Total
THEN '%D1'
ELSE '%SS'
END
OR Test LIKE
CASE WHEN D1D2_Total > SS_Total
THEN '%D2'
ELSE '%SS'
END
select *, case when SS >= DX then SS else DX end
from T cross apply (values (
sum(case when Test = 'TW01SS1' then Value end)
over (partition by RecordNumber),
sum(case when Test like 'TW01D[12]' then Value end)
over (partition by RecordNumber))
) s(SS, DX);
You can use else coalesce(DX, SS) if null/missing tests are at play.
As an update:
update T
set Complement = (
select case when SS >= DX then SS else DX end
from T t2 cross apply (values (
sum(case when Test = 'TW01SS1' then Value end),
sum(case when Test like 'TW01D[12]' then Value end)
) s(SS, DX)
where t2.RecordNumber = T.RecordNumber
);

Transpose row value to additional pre-defined field when value is less than specified value

I have a table that contains two identifying columns, a date, and a value. This value can be up to 100. What I want to do is where [ID] and [DATE] is the same across subsequent rows and the values are less than 100 (which also means [ID_SECONDARY] is always different), I want a query to place each one of these values in a column '[VALUE_1]...[VALUE_N]' along with the Value Description ([ID_SECONDARY]-->[VALUE_1_DESC]...[VALUE_N_DESC]). Ultimately each row should contain a unique [ID], [DATE], and an aggregation of the different [ID_SECONDARY] descriptions along with their values [VALUE_1]...[VALUE_N]. The number of unique [ID_SECONDARY] will not surpass 4, but could be from 1 to 4.
My initial inclination is to approach this using a cursor, but am hopeful there is a better alternative.
The first image is a sample of the information provided in the table, the second image is the output I'm looking for. Any help is greatly appreciated.
.
As far as I can tell this is different from the various dynamic pivot posts out there because the columns are independent of the secondary ID and are fully dependent on the VALUE column to determine if the value itself belongs in columns 1-4.
Try this
WITH a AS (
SELECT
ID
, [DATE]
, ID_SECONDARY
, VALUE
, ROW_NUMBER() OVER (PARTITION BY ID, DATE ORDER BY ID) AS RNUM
)
SELECT
a.ID
, a.[DATE]
, MAX (
CASE a.RNUM
WHEN 1 THEN a.VALUE
ELSE NULL
) AS VALUE_1
, MAX (
CASE a.RNUM
WHEN 1 THEN a.ID_SECONDARY
ELSE NULL
) AS VALUE_1_DESC
, MAX (
CASE a.RNUM
WHEN 2 THEN a.VALUE
ELSE NULL
) AS VALUE_2
, MAX (
CASE a.RNUM
WHEN 2 THEN a.ID_SECONDARY
ELSE NULL
) AS VALUE_2_DESC
, MAX (
CASE RNUM
WHEN 3 THEN a.VALUE
ELSE NULL
) AS VALUE_3
, MAX (
CASE RNUM
WHEN 3 THEN a.ID_SECONDARY
ELSE NULL
) AS VALUE_3_DESC
, MAX (
CASE RNUM
WHEN 4 THEN a.VALUE
ELSE NULL
) AS VALUE_4
, MAX (
CASE RNUM
WHEN 4 THEN a.ID_SECONDARY
ELSE NULL
) AS VALUE_4_DESC
FROM a
GROUP BY a.ID, a.[DATE]

Joining a Temp Table to Actual Table

I need to verify that each order has been acknowledged. The problem is that each order can have multiple codes. The query I had (utilizing a CASE statement) would check for blank fields or fields with the string "None" to verify the order has not been acknowledged. It would return the appropriate result, but multiple rows (once for each possible response) and I only need (1).
I'm attempting to create a temp table that will return the appropriate result and join (via an order unique ID) the two tables together hoping to correct the multiple row issue. Here is the code:
DROP TABLE staging_TABLE;
CREATE TEMP TABLE staging_TABLE(
ORDERID varchar(256) ,
CODE varchar(256) );
/*Keeping data types consistent with the real table*/
INSERT INTO staging_TABLE
SELECT ORDERID,
CASE CODE
WHEN 'None' THEN 'No'
WHEN '' THEN 'No'
ELSE 'Yes'
END
FROM ORDERS
WHERE UTCDATE > SYSDATE - 10
AND CODE IS NOT NULL;
SELECT R.QUESTION,
R.ORDERNAME,
T.CODE
FROM ORDERS R
INNER JOIN staging_TABLE T
ON R.ORDERID= T.ORDERID
WHERE R.UTCDATE > SYSDATE - 10
AND R.CODE IS NOT NULL
AND R.CATEGORY IS NOT NULL
AND R.UTCDATE IS NOT NULL
GROUP BY
R.ORDER,
T.CODE,
R.ORDERNAME,
R.CODE
ORDER BY
R.ORDERNAME,
R.ORDER;
Am I doing this correctly? Or is this even the right approach?
Am I doing this correctly? Or is this even the right approach?
No. You don't need a temp table for this. Your query might look like this:
SELECT question, ordername
, CASE WHEN code IN ('None', '') THEN 'No' ELSE 'Yes' END AS code
FROM orders
WHERE utcdate > sysdate - 10
AND code IS NOT NULL
AND category IS NOT NULL
GROUP BY question, ordername, 3, "order"
ORDER BY ordername, "order";
ORDER is a reserved word. It's not possible to use it as column name unless double quoted. There is something wrong there.
AND R.UTCDATE IS NOT NULL is redundant. It can't be NULL anyway with WHERE R.UTCDATE > SYSDATE - 10
3 in my GROUP BY clause is a positional reference to the CASE expression. Alternatively you can spell it out again:
....
GROUP BY question, ordername
, CASE WHEN code IN ('None', '') THEN 'No' ELSE 'Yes' END
, "order"
You can use the DISTINCT keyword as follows so you will not need a temp table:
SELECT DISTINCT QUESTION,
ORDERNAME,
CASE CODE
WHEN 'None' THEN 'No'
WHEN '' THEN 'No'
ELSE 'Yes'
FROM ORDERS
WHERE UTCDATE > SYSDATE - 10
AND CODE IS NOT NULL
AND CATEGORY IS NOT NULL
AND UTCDATE IS NOT NULL
ORDER BY 2,3;

Coalesce function not selecting data value from series when it exists

My code is as follows:
Insert Into dbo.database (Period, Amount)
Select coalesce (date_1, date_2, date_3), Amount FROM Source.dbo.[10]
I'm 100% a value exists in one of the 3 variables: date_1, date_2, date_3, all as strings (var char 100), yet I am still getting blanks when I call Period.
Any help?
Coalesce is designed to return the first NOT NULL field from the list or NULL if none of the fields are NOT NULL, follow the link for full details http://msdn.microsoft.com/en-us/library/ms190349.aspx
I would guess that you have blank values (' ') in one of the columns instead of NULL values. If you are trying to find the first not null non-blank column you can use a case statement.
select
case
when len(rtrim(ltrim(date_1))) > 0 then date_1
when len(rtrim(ltrim(date_2))) > 0 then date_2
when len(rtrim(ltrim(date_3))) > 0 then date_3
else null
end,
Amount
from Source.dbo.[10]

Counting null and non-null values in a single query

I have a table
create table us
(
a number
);
Now I have data like:
a
1
2
3
4
null
null
null
8
9
Now I need a single query to count null and not null values in column a
This works for Oracle and SQL Server (you might be able to get it to work on another RDBMS):
select sum(case when a is null then 1 else 0 end) count_nulls
, count(a) count_not_nulls
from us;
Or:
select count(*) - count(a), count(a) from us;
If I understood correctly you want to count all NULL and all NOT NULL in a column...
If that is correct:
SELECT count(*) FROM us WHERE a IS NULL
UNION ALL
SELECT count(*) FROM us WHERE a IS NOT NULL
Edited to have the full query, after reading the comments :]
SELECT COUNT(*), 'null_tally' AS narrative
FROM us
WHERE a IS NULL
UNION
SELECT COUNT(*), 'not_null_tally' AS narrative
FROM us
WHERE a IS NOT NULL;
Here is a quick and dirty version that works on Oracle :
select sum(case a when null then 1 else 0) "Null values",
sum(case a when null then 0 else 1) "Non-null values"
from us
for non nulls
select count(a)
from us
for nulls
select count(*)
from us
minus
select count(a)
from us
Hence
SELECT COUNT(A) NOT_NULLS
FROM US
UNION
SELECT COUNT(*) - COUNT(A) NULLS
FROM US
ought to do the job
Better in that the column titles come out correct.
SELECT COUNT(A) NOT_NULL, COUNT(*) - COUNT(A) NULLS
FROM US
In some testing on my system, it costs a full table scan.
As i understood your query, You just run this script and get Total Null,Total NotNull rows,
select count(*) - count(a) as 'Null', count(a) as 'Not Null' from us;
usually i use this trick
select sum(case when a is null then 0 else 1 end) as count_notnull,
sum(case when a is null then 1 else 0 end) as count_null
from tab
group by a
Just to provide yet another alternative, Postgres 9.4+ allows applying a FILTER to aggregates:
SELECT
COUNT(*) FILTER (WHERE a IS NULL) count_nulls,
COUNT(*) FILTER (WHERE a IS NOT NULL) count_not_nulls
FROM us;
SQLFiddle: http://sqlfiddle.com/#!17/80a24/5
This is little tricky. Assume the table has just one column, then the Count(1) and Count(*) will give different values.
set nocount on
declare #table1 table (empid int)
insert #table1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(NULL),(11),(12),(NULL),(13),(14);
select * from #table1
select COUNT(1) as "COUNT(1)" from #table1
select COUNT(empid) "Count(empid)" from #table1
Query Results
As you can see in the image, The first result shows the table has 16 rows. out of which two rows are NULL. So when we use Count(*) the query engine counts the number of rows, So we got count result as 16. But in case of Count(empid) it counted the non-NULL-values in the column empid. So we got the result as 14.
so whenever we are using COUNT(Column) make sure we take care of NULL values as shown below.
select COUNT(isnull(empid,1)) from #table1
will count both NULL and Non-NULL values.
Note: Same thing applies even when the table is made up of more than one column. Count(1) will give total number of rows irrespective of NULL/Non-NULL values. Only when the column values are counted using Count(Column) we need to take care of NULL values.
I had a similar issue: to count all distinct values, counting null values as 1, too. A simple count doesn't work in this case, as it does not take null values into account.
Here's a snippet that works on SQL and does not involve selection of new values.
Basically, once performed the distinct, also return the row number in a new column (n) using the row_number() function, then perform a count on that column:
SELECT COUNT(n)
FROM (
SELECT *, row_number() OVER (ORDER BY [MyColumn] ASC) n
FROM (
SELECT DISTINCT [MyColumn]
FROM [MyTable]
) items
) distinctItems
Try this..
SELECT CASE
WHEN a IS NULL THEN 'Null'
ELSE 'Not Null'
END a,
Count(1)
FROM us
GROUP BY CASE
WHEN a IS NULL THEN 'Null'
ELSE 'Not Null'
END
Here are two solutions:
Select count(columnname) as countofNotNulls, count(isnull(columnname,1))-count(columnname) AS Countofnulls from table name
OR
Select count(columnname) as countofNotNulls, count(*)-count(columnname) AS Countofnulls from table name
Try
SELECT
SUM(ISNULL(a)) AS all_null,
SUM(!ISNULL(a)) AS all_not_null
FROM us;
Simple!
If you're using MS Sql Server...
SELECT COUNT(0) AS 'Null_ColumnA_Records',
(
SELECT COUNT(0)
FROM your_table
WHERE ColumnA IS NOT NULL
) AS 'NOT_Null_ColumnA_Records'
FROM your_table
WHERE ColumnA IS NULL;
I don't recomend you doing this... but here you have it (in the same table as result)
use ISNULL embedded function.
All the answers are either wrong or extremely out of date.
The simple and correct way of doing this query is using COUNT_IF function.
SELECT
COUNT_IF(a IS NULL) AS nulls,
COUNT_IF(a IS NOT NULL) AS not_nulls
FROM
us
SELECT SUM(NULLs) AS 'NULLS', SUM(NOTNULLs) AS 'NOTNULLs' FROM
(select count(*) AS 'NULLs', 0 as 'NOTNULLs' FROM us WHERE a is null
UNION select 0 as 'NULLs', count(*) AS 'NOTNULLs' FROM us WHERE a is not null) AS x
It's fugly, but it will return a single record with 2 cols indicating the count of nulls vs non nulls.
This works in T-SQL. If you're just counting the number of something and you want to include the nulls, use COALESCE instead of case.
IF OBJECT_ID('tempdb..#us') IS NOT NULL
DROP TABLE #us
CREATE TABLE #us
(
a INT NULL
);
INSERT INTO #us VALUES (1),(2),(3),(4),(NULL),(NULL),(NULL),(8),(9)
SELECT * FROM #us
SELECT CASE WHEN a IS NULL THEN 'NULL' ELSE 'NON-NULL' END AS 'NULL?',
COUNT(CASE WHEN a IS NULL THEN 'NULL' ELSE 'NON-NULL' END) AS 'Count'
FROM #us
GROUP BY CASE WHEN a IS NULL THEN 'NULL' ELSE 'NON-NULL' END
SELECT COALESCE(CAST(a AS NVARCHAR),'NULL') AS a,
COUNT(COALESCE(CAST(a AS NVARCHAR),'NULL')) AS 'Count'
FROM #us
GROUP BY COALESCE(CAST(a AS NVARCHAR),'NULL')
Building off of Alberto, I added the rollup.
SELECT [Narrative] = CASE
WHEN [Narrative] IS NULL THEN 'count_total' ELSE [Narrative] END
,[Count]=SUM([Count]) FROM (SELECT COUNT(*) [Count], 'count_nulls' AS [Narrative]
FROM [CrmDW].[CRM].[User]
WHERE [EmployeeID] IS NULL
UNION
SELECT COUNT(*), 'count_not_nulls ' AS narrative
FROM [CrmDW].[CRM].[User]
WHERE [EmployeeID] IS NOT NULL) S
GROUP BY [Narrative] WITH CUBE;
SELECT
ALL_VALUES
,COUNT(ALL_VALUES)
FROM(
SELECT
NVL2(A,'NOT NULL','NULL') AS ALL_VALUES
,NVL(A,0)
FROM US
)
GROUP BY ALL_VALUES
select count(isnull(NullableColumn,-1))
if its mysql, you can try something like this.
select
(select count(*) from TABLENAME WHERE a = 'null') as total_null,
(select count(*) from TABLENAME WHERE a != 'null') as total_not_null
FROM TABLENAME
Just in case you wanted it in a single record:
select
(select count(*) from tbl where colName is null) Nulls,
(select count(*) from tbl where colName is not null) NonNulls
;-)
for counting not null values
select count(*) from us where a is not null;
for counting null values
select count(*) from us where a is null;
I created the table in postgres 10 and both of the following worked:
select count(*) from us
and
select count(a is null) from us
In my case I wanted the "null distribution" amongst multiple columns:
SELECT
(CASE WHEN a IS NULL THEN 'NULL' ELSE 'NOT-NULL' END) AS a_null,
(CASE WHEN b IS NULL THEN 'NULL' ELSE 'NOT-NULL' END) AS b_null,
(CASE WHEN c IS NULL THEN 'NULL' ELSE 'NOT-NULL' END) AS c_null,
...
count(*)
FROM us
GROUP BY 1, 2, 3,...
ORDER BY 1, 2, 3,...
As per the '...' it is easily extendable to more columns, as many as needed
Number of elements where a is null:
select count(a) from us where a is null;
Number of elements where a is not null:
select count(a) from us where a is not null;