Check if a column value is updated to NULL - sql-server

I have to determine if a column has been updated from a NOT NULL value to NULL in sql server.
Example -
UpdateDate Value Individual
2020-09-02 10:39:03.530 NULL 105292933
2020-08-31 11:05:06.053 Y 105292933
2020-08-31 11:04:32.720 N 105292931
In above example, for Individual 105292933, Value has been updated to NULL from Y. So the result should be the first row. I am new to sql server. Here is what I tried to get the result -
SELECT a.*
FROM tableX AS a
WHERE a.Value <>
( SELECT TOP 1 b.Value
FROM tableX AS b
WHERE a.Individual = b.Individual
AND a.UpdateDate > b.UpdateDate
ORDER BY b.UpdateDate DESC
)
But it is not picking the changes from Y to NULL or N to NULL. Any help will be appreciated.

You can't compare a value with NULL, You can only compare something that is (strings, numbers etc).
In SQL Server NULL != NULL. To check if value is null use WHERE a.value IS NULL
You can change Your code to compare column with some special string (or empty string if You like) if its value is NULL using ISNULL() function.
SELECT a.*
FROM tableX AS a
WHERE ISNULL(a.Value, '*NULL*') <>
( SELECT TOP 1 ISNULL(b.Value, '*NULL*')
FROM tableX AS b
WHERE a.Individual = b.Individual
AND a.UpdateDate > b.UpdateDate
ORDER BY b.UpdateDate DESC
)
A litter more about NULL values here https://www.w3schools.com/sql/sql_null_values.asp

Window functions are usually more efficient than subqueries, when applicable. I would recommend lag():
select *
from (
select t.*, lag(value) over(partition by individual order by updatedate) lag_value
from mytable t
) t
where value is null and lag_value is not null

This query identifies rows were the prior value (based on UpdateDate) was 'Y' or 'N'. Something like this
with lag_cte as (
select *, lag([value]) over(partition by individual order by updatedate) lag_value
from tableX)
select *
from lag_cte
where value is null
and lag_value in('N', 'Y');

Related

Can't get rows that have same code type and same ZPLID and feature key have both Null and values?

I work with SQL Server 2012. I can't get rows from table #gen when they have rows with at least one NULL and at least on non-NULL value in the feature key column, based on Zplid and CodeTypeId.
Meaning I need to get rows that have NULL in the feature key and values in the feature key but must be same CodeTypeId and same Zplid.
create table #gen
(
CodeTypeId int,
Zplid int,
Zfeaturekey nvarchar(50)
)
insert into #gen
values (854838, 25820, NULL),
(849774, 25820, 1502260001),
(849774, 25820, 1502260001),
(849774, 25820, 1502260016),
(849774, 25820, NULL),
(987431, 26777, 1502270003),
(987431, 26777, 1502280005),
(987431, 26777, 1502290001)
This is the result I need :
CodeTypeId Zplid Zfeaturekey
------------------------------------
849774 25820 1502260001
849774 25820 1502260001
849774 25820 1502260016
849774 25820 NULL
I will not get rows with CodeTypeId = 854838 and Zplid = 25820 because they have NULL only in the feature key.
I will not get rows with CodeTypeId = 987431 and Zplid = 26777 because they do not have NULL in the feature key .
The basic approach for this would be to
a) find the combinations of CodeTypeID and Zplid that have both a NULL and a non-NULL
b) report all rows for that combination of combinations of CodeTypeID and Zplid
For example
SELECT g.*
FROM #gen g
INNER JOIN
(SELECT CodeTypeId, Zplid
FROM #gen
GROUP BY CodeTypeId, Zplid
HAVING COUNT(*) > COUNT(Zfeaturekey)
AND COUNT(Zfeaturekey) >= 1
) AS g_filtered
ON g.CodeTypeId = g_filtered.CodeTypeId
AND g.Zplid= g_filtered.Zplid
Here is a db<>fiddle
You can use window functions. The idea is to count all the values per codetyped and to compare that to the count of non-null values. Then, we can use that information to ensure that there is at least one non-null value and one null value per group.
select *
from (
select g.*,
count(*) over(partition by codetypeid) cnt,
count(zfeaturekey) over(partition by codetypeid) cnt_not_nulls
from #gen g
) g
where cnt > cnt_not_nulls and cnt_not_nulls > 0
Using a CTE can make the code simpler and more intuitive:
with cte
as(SELECT CodeTypeId, Zplid
FROM #gen
GROUP BY CodeTypeId, Zplid)
SELECT g.* FROM #gen g
JOIN cte c
ON g.CodeTypeId = g_filtered.CodeTypeId AND g.Zplid= g_filtered.Zplid
WHERE COUNT(c.*) > COUNT(c.Zfeaturekey)
AND COUNT(c.Zfeaturekey) >= 1

T-SQL grouping values on multiple columns and return row values as columns

I have a dataset which returns a number of row, 2 columns RoomType and FaultTypeName should be grouped but those 2 columns also have 1 'Result' column. Because of the 'Result' column the grouping will fail. So to make it clearer, the result set looks as follows:
The FaultTypeName are always the same three values 'Methode (M)', 'Periodiek (P)' or Vuil (V). These values should be returned as new columns with respectively their result values. So above resultset should be returned as following:
I already tried to do something with the rownumber (hence the rn column) but this didn't quite work out:
select
...
from(
select MeasurementId, RoomType, FaultTypeName, Result,
row_number() over(partition by RoomType order by RoomType, FaultTypeName) rn
from vwReportData
where measurementid = 1382596
)sub
There is a possibility that only 2 (or less) of the 3 columns (Methode, Periodiek and Vuil) are returned instead of all 3 (so less rows), if this is the case, the missing FaultTypeName(s) should still be added as column but with a result of 0.
Any ideas how I can get the right output?
Try this:
select *
from
(
select MeasurementId, RoomType, FaultTypeName, Result,
row_number() over(partition by RoomType order by RoomType, FaultTypeName) rn
from vwReportData
where measurementid = 1382596
) DS
PIVOT
(
MAX(result) for rn in ([1], [2], [3])
) PVT
In the end I figured it out myself:
SELECT
MeasurementId,
RoomType,
M = ISNULL(MIN(CASE WHEN FaultTypeName = 'Methode (M)' THEN Result ELSE NULL END), 0),
P = ISNULL(MIN(CASE WHEN FaultTypeName = 'Periodiek (P)' THEN Result ELSE NULL END), 0),
V = ISNULL(MIN(CASE WHEN FaultTypeName = 'Vuil (V)' THEN Result ELSE NULL END), 0)
FROM vwReportData
WHERE MeasurementId = 1382596
GROUP BY MeasurementId, RoomType

Subquery reference newly created column

I have been trying to write a subquery based on the SQL Server docs. I am trying to write a SQL Server query to
cast a varchar to an int
select rows where the varchar is null.
My logic is:
outer select+ where clause gets all rows where the new column (q5int) is NULL
create inner select that performs the cast and creates the new column (q5int)
What am I doing wrong? I would appreciate an explanation of whats wrong with my logic, not just how to fix my code.
select *
from
(select
*, cast (NULLIF(q5,'NULL') as int) as q5int
from
ft_merge)
where
q5int = NULL
You can do this sans the sub-query
select *
from ft_merge
WHERE try_convert(int,q5) is null
Let us analyze your query first
select * from (
select *,cast (NULLIF(q5,'NULL') as int) as q5int
from ft_merge
) WHERE q5int=NULL
1.NULLIF(q5,'NULL') should be NULLIF(q5,NULL) not in quotes
2.WHERE q5int=NULL should be replaced with "q5int IS NULL"
Creating test data
Select * into #ft_merge
from
(
Select 1 AS ID,'111' AS q5
union
Select 2, null
union
Select 3,'2222'
union
Select 4,null
)t
/* using your query */
select * from (
select *,cast(q5 as int) as q5int
from #ft_merge where ISNUMERIC(q5) > 0 or q5 is null
)t WHERE q5int is NULL
/* another optimal way of doing this */
select *,cast(q5 as int) as q5int
from #ft_merge where NULLIF(q5,NULL) is null

Incorrect Syntax in sql server , can't figure out the reason

I'm trying to uodate a column in table , depending on combination of two columns.If the value was null , since beginning of time I set it to 0 otherwise I set it to max value until that date.I'm using SQL SERVER 2008.Thanks for the help in advance!
update Table1
set value = a.value
from
( SELECT product,
week ,
case when value is null then
(case when max(value) over(PARTITION BY product ORDER BY week ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) is null then 0
else (max(value) over (PARTITION BY product ORDER BY week ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)) end )
else value end as value
from table2 ) a
where a.product = table1.product
and a.week = table1.week
The ROWS keyword was added to the OVER clause in 2012. You won't be able to use it for 2008.
https://msdn.microsoft.com/en-us/library/ms189461(v=sql.110).aspx

SQL SELECT Ordering columns with Null Values

My question is similar to this one: How to display a table order by code (like 01, 02… then null columns)?, but for SQL Server.
In short, I have a SELECT statement, that returns the following:
ColumnA ColumnB
X NULL
Y 1
Z 2
..where the ordering is done by ColumnB.
How can we force the (columnB = NULL) type of rows to the bottom? ie, the expected result is this:
ColumnA ColumnB
Y 1
Z 2
X NULL
Thank you SOF community.
...or in order to avoid value clashing...
SELECT
ColumnA,
ColumnB
FROM YourTable
ORDER BY
CASE WHEN ColumnB IS NULL THEN 1 ELSE 0 END ASC,
ColumnB
You can also use isnull:
select * from thetable order by isnull(columnb, 99999)
isnull will replace null with the value you provide to it, so in this case, if the column is null, it will replace it with 99999. You can set the value to some big number so it will be at the bottom of the order.
hoping to help someone,
I just wanted to add that I have had a similiar issue, using row_number and partition by -
when it is zero put it at the end sort of thing
and I used the script below (partial view):
,T.MONTHS_TO_AUTOGROWTH
,the_closest_event=ROW_NUMBER() OVER (PARTITION BY SERVERID, DRIVE ORDER BY
CASE WHEN MONTHS_TO_AUTOGROWTH > 0 THEN MONTHS_TO_AUTOGROWTH ELSE 9999
END )
the result is ordered by MONTHS_TO_AUTOGROWTH but zero comes last

Resources