How to Compare null value with some value in SQL? - sql

i have question about how can i compare the getting value is null and compare in if condition in sql like
here is my data null value bcz i have no data in custId when i use this query its right Select custId from myTable where Id=123 but how to compare null to the value? also some time values in row show both condition applicable it mean some custId data available also update custId in ..query in this condition when it will be true
IF (Select custId from myTable where Id=#Id) != #custId
BEGIN
...query
END

Maybe this code below will work? This accounts for both sides of the custId equation possibly being null. You will want to use a value that can't possibly be in your custId data, hence the negative number since most id's are positive.
IF EXISTS
(SELECT
1
FROM
myTable
WHERE
Id = #Id
AND ISNULL(custId, -1) = ISNULL(#custId, -1))
BEGIN
...query
END;

Related

Trying to INSERT to based on CASE statement with SELECT VALUE

I Have a list of of SpellIDs with corresponding M values.
Given by the statement
SELECT TOP(1000) Spell_ID, MAX(Episode_Order) as M
From [dbo].[Client_MidEssex_Inpatient_Episodes_Landing]
GROUP BY Spell_ID
output
What I want to is to INSERT on the Episode Order Column on my Inpatients_episodes_table, a value depending on the M column from the select statement, on the corresponding spell_IDs. (Each row has a spell ID and Episode order value)
The logic is:For each spell ID value in the table Check the corresponding spellID in the select statement and -> check M value. Then Compare M value from the select statement to the Episode Order value from the table. Based on this comparison, insert either a discharge or admittance code
I am trying to relate the select statement and the table both on spell_IDs, but I'm not too how.
So far I have this:
UPDATE Inpatient_Episodes_Landing SET Episode_Ward = Null;
INSERT INTO [dbo].[Inpatient_Episodes_Landing] ([Episode_Ward])
SELECT
(Case when Episode_Order=01 then Admission_Ward_Code
when Episode_Order = (SELECT Spell_ID, MAX(Episode_Order) as M
From [dbo].[Client_MidEssex_Inpatient_Episodes_Landing]
where Spell_ID = (select SpellID from [dbo].[Inpatient_Episodes_Landing])
GROUP BY Spell_ID ) then Discharge_Ward_Code
else Admission_Ward_Code
END)
FROM [dbo].[Client_MidEssex_Inpatient_Episodes_Landing]
Select TOP (1000) SpellID,Episode_Number,Episode_Ward from Inpatient_Episodes_Landing
Any help would be great, thank you!

T-SQL UPDATE statement affects less records than select statement

I am trying to update a DateTime column of one table with a date column from another table.
Before updating it, I am getting the records affected in order to see previously what records will be affected in the UPDATE. So I perform a SELECT statement with below WHERE clause:
NOTE:
DateTimeField is of type DateTime
DateField is of type Date
Code:
SELECT tblToUpdate.*
FROM MyTable1 tblToUpdate
INNER JOIN MyTable2 fromTbl on tblToUpdate.Id = fromTbl.Id
WHERE
ISNULL(fromTbl.DateField, GETDATE()) >= DATEFROMPARTS(1753, 1, 1)
AND ((fromTbl.DateField IS NOT NULL AND tblToUpdate.DateTimeField IS NULL)
OR
(fromTbl.DateField IS NULL AND tblToUpdate.DateTimeField IS NOT NULL)
OR
fromTbl.DateField <> CAST(tblToUpdate.DateTimeField AS DATE))
UPDATE tblToUpdate
SET tblToUpdate.DateTimeField = fromTbl.DateField
FROM MyTable1 tblToUpdate
INNER JOIN MyTable2 fromTbl ON tblToUpdate.Id = fromTbl.Id
WHERE
ISNULL(fromTbl.DateField, GETDATE()) >= DATEFROMPARTS(1753, 1, 1)
AND (
(fromTbl.DateField IS NOT NULL AND tblToUpdate.DateTimeField IS NULL)
OR
(fromTbl.DateField IS NULL AND tblToUpdate.DateTimeField IS NOT NULL)
OR
fromTbl.DateField <> CAST(tblToUpdate.DateTimeField AS DATE)
)
Note that I check DateField in Where clause to be in DateTime range before I update it.
The problem is that the number of records returned by the SELECT statement is not the same as the number of records affected returned by UPDATE statement.
The UPDATE statement affects fewer records than the SELECT statement returns.
Why is it happening if from and where clause are the same in both statements?
I think the number of records returned by SELECT and affected by UPDATE statements respectively should be the same.
This is easy to demonstrate. When there are multiple rows meeting the join predicates you will get differing row counts from a select and an update.
create table Header(HeadID int identity, Name varchar(50))
insert Header select 'test'
create table Details(DetailsID int identity, HeadID int, Name varchar(50))
insert Details values(1, 'asdf'),(1,'qwer')
select * --this returns 2 rows
from Header h
join Details d on d.HeadID = h.HeadID
update h --only 1 row affected
set Name = 'what?'
from Header h
join Details d on d.HeadID = h.HeadID

Check for same character value in column

I'm trying to verify when a column has all the same values for the same group. Here is a sample of my table data:
So using this data, for example. I want to check to see if all values of Status is the same for every row with the same TPID. So TPID 60210 should result with True since both items have a Status of A. However, TPID 60061 should result in false since two of the Line_Item show A and the rest P.
I intend to update a different table using this information, setting its status using a CASE statement. But I'm at a loss how to check against this column to find the values I desire.
;WITH CTE_Count
AS
(
SELECT TPID, COUNT(DISTINCT Status) CNT
FROM TableName
GROUP BY TPID
)
UPDATE AnotherTableName
SET ColumnName = (
CASE WHEN CTE_Count.CNT = 1 -- all row has same status
THEN SomeValue
ELSE SomeOtherValue END
)
FROM AnotherTableName
INNER JOIN CTE_Count ON ...

Doing a join only if count is greater than one

I wonder if the following a bit contrived example is possible without using intermediary variables and a conditional clause.
Consider an intermediary query which can produce a result set that contain either no rows, one row or multiple rows. Most of the time it produces just one row, but when multiple rows, one should join the resulting rows to another table to prune it down to either one or no rows. After this if there is one row (as opposed to no rows), one would want to return multiple columns as produced by the original intermediary query.
I have in my mind something like following, but it won't obviously work (multiple columns in switch-case, no join etc.), but maybe it illustrates the point. What I would like to have is to just return what is currently in the SELECT clause in case ##ROWCOUNT = 1 or in case it is greater, do a INNER JOIN to Auxilliary, which prunes down x to either one row or no rows and then return that. I don't want to search Main more than once and Auxilliary only when x here contains more than one row.
SELECT x.MainId, x.Data1, x.Data2, x.Data3,
CASE
WHEN ##ROWCOUNT IS NOT NULL AND ##ROWCOUNT = 1 THEN
1
WHEN ##ROWCOUNT IS NOT NULL AND ##ROWCOUNT > 1 THEN
-- Use here #id or MainId to join to Auxilliary and there
-- FilteringCondition = #filteringCondition to prune x to either
-- one or zero rows.
END
FROM
(
SELECT
MainId,
Data1,
Data2,
Data3
FROM Main
WHERE
MainId = #id
) AS x;
CREATE TABLE Main
(
-- This Id may introduce more than row, so it is joined to
-- Auxilliary for further pruning with the given conditions.
MainId INT,
Data1 NVARCHAR(MAX) NOT NULL,
Data2 NVARCHAR(MAX) NOT NULL,
Data3 NVARCHAR(MAX) NOT NULL,
AuxilliaryId INT NOT NULL
);
CREATE TABLE Auxilliary
(
AuxilliaryId INT IDENTITY(1, 1) PRIMARY KEY,
FilteringCondition NVARCHAR(1000) NOT NULL
);
Would this be possible in one query without a temporary table variable and a conditional? Without using a CTE?
Some sample data would be
INSERT INTO Auxilliary(FilteringCondition)
VALUES
(N'SomeFilteringCondition1'),
(N'SomeFilteringCondition2'),
(N'SomeFilteringCondition3');
INSERT INTO Main(MainId, Data1, Data2, Data3, AuxilliaryId)
VALUES
(1, N'SomeMainData11', N'SomeMainData12', N'SomeMainData13', 1),
(1, N'SomeMainData21', N'SomeMainData22', N'SomeMainData23', 2),
(2, N'SomeMainData31', N'SomeMainData32', N'SomeMainData33', 3);
And a sample query, which actually behaves as I'd like it to behave with the caveat I'd want to do the join only if querying Main directly with the given ID produces more than one result.
DECLARE #id AS INT = 1;
DECLARE #filteringCondition AS NVARCHAR(1000) = N'SomeFilteringCondition1';
SELECT *
FROM
Main
INNER JOIN Auxilliary AS aux ON aux.AuxilliaryId = Main.AuxilliaryId
WHERE MainId = #id AND aux.FilteringCondition = #filteringCondition;
You don't usually use a join to reduce the result set of the left table. To limit a result set you'd use the where clause instead. In combination with another table this would be WHERE [NOT] EXISTS.
So let's say this is your main query:
select * from main where main.col1 = 1;
It returns one of the following results:
no rows, then we are done
one row, then we are also done
more than one row, then we must extend the where clause
The query with the extended where clause:
select * from main where main.col1 = 1
and exists (select * from other where other.col2 = main.col3);
which returns one of the following results:
no rows, which is okay
one row, which is okay
more than one row - you say this is not possible
So the task is to do this in one step instead. I count records and look for a match in the other table for every record. Then ...
if the count is zero we get no result anyway
if it is one I take that row
if it is greater than one, I take the row for which exists a match in the other table or none when there is no match
Here is the full query:
select *
from
(
select
main.*,
count(*) over () as cnt,
case when exists (select * from other where other.col2 = main.col3) then 1 else 0 end
as other_exists
from main
where main.col1 = 1
) counted_and_checked
where cnt = 1 or other_exists = 1;
UPDATE: I understand that you want to avoid unnecessary access to the other table. This is rather difficult to do however.
In order to only use the subquery when necessary, we could move it outside:
select *
from
(
select
main.*,
count(*) over () as cnt
from main
where main.col1 = 1
) counted_and_checked
where cnt = 1 or exists (select * from other where other.col2 = main.col3);
This looks much better in my opinion. However there is no precedence among the two expressions left and right of an OR. So the DBMS may still execute the subselect on every record before evaluating cnt = 1.
The only operation that I know of using left to right precedence, i.e. doesn't look further once a condition on the left hand side is matched is COALESCE. So we could do the following:
select *
from
(
select
main.*,
count(*) over () as cnt
from main
where main.col1 = 1
) counted_and_checked
where coalesce( case when cnt = 1 then 1 else null end ,
(select count(*) from other where other.col2 = main.col3)
) > 0;
This may look a bit strange, but should prevent the subquery from being executed, when cnt is 1.
You may try something like
select * from Main m
where mainId=#id
and #filteringCondition = case when(select count(*) from Main m2 where m2.mainId=#id) >1
then (select filteringCondition from Auxilliary a where a.AuxilliaryId = m.AuxilliaryId) else #filteringCondition end
but it's hardly very fast query. I'd better use temp table or just if and two queries.

I am looking for a way for a trigger to insert into a second table only where the value in table 1 changes

I am looking for a way for a trigger to insert into a second table only where the value in table 1 changes. It is essentially an audit tool to trap any changes made. The field in table 1 is price and we want to write additional fields.
This is what I have so far.
CREATE TRIGGER zmerps_Item_costprice__update_history_tr ON [ITEM]
FOR UPDATE
AS
insert into zmerps_Item_costprice_history
select NEWID(), -- unique id
GETDATE(), -- CURRENT_date
'PRICE_CHANGE', -- reason code
a.ima_itemid, -- item id
a.ima_price-- item price
FROM Inserted b inner join item a
on b.ima_recordid = a.IMA_RecordID
The table only contains a unique identifier, date, reference(item) and the field changed (price). It writes any change not just a price change
Is it as simple as this? I moved some of the code around because comments after the comma between columns is just painful to maintain. You also should ALWAYS specify the columns in an insert statement. If your table changes this code will still work.
CREATE TRIGGER zmerps_Item_costprice__update_history_tr ON [ITEM]
FOR UPDATE
AS
insert into zmerps_Item_costprice_history
(
UniqueID
, CURRENT_date
, ReasonCode
, ItemID
, ItemPrice
)
select NEWID()
, GETDATE()
, 'PRICE_CHANGE'
, d.ima_itemid
, d.ima_price
FROM Inserted i
inner join deleted d on d.ima_recordid = i.IMA_RecordID
AND d.ima_price <> i.ima_price
Since you haven't provided any other column names I Have used Column2 and Column3 and the "Other" column names in the below example.
You can expand adding more columns in the below code.
overview about the query below:
Joined the deleted and inserted table (only targeting the rows that has changed) joining with the table itself will result in unnessacary processing of the rows which hasnt changed at all.
I have used NULLIF function to yeild a null value if the value of the column hasnt changed.
converted all the columns to same data type (required for unpivot) .
used unpivot to eliminate all the nulls from the result set.
unpivot will also give you the column name its has unpivoted it.
CREATE TRIGGER zmerps_Item_costprice__update_history_tr
ON [ITEM]
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON ;
WITH CTE AS (
SELECT CAST(NULLIF(i.Price , d.Price) AS NVARCHAR(100)) AS Price
,CAST(NULLIF(i.Column2 , d.Column2) AS NVARCHAR(100)) AS Column2
,CAST(NULLIF(i.Column3 , d.Column3) AS NVARCHAR(100)) AS Column3
FROM dbo.inserted i
INNER JOIN dbo.deleted d ON i.IMA_RecordID = d.IMA_RecordID
WHERE i.Price <> d.Price
OR i.Column2 <> d.Column2
OR i.Column3 <> d.Column3
)
INSERT INTO zmerps_Item_costprice_history
(unique_id, [CURRENT_date], [reason code], Item_Value)
SELECT NEWID()
,GETDATE()
,Value
,ColumnName + '_Change'
FROM CTE UNPIVOT (Value FOR ColumnName IN (Price , Column2, Column3) )up
END
As I understand your question correctly, You want to record change If and only if The column Price value is changes, you dont need any other column changes to be recorded
here is your code
CREATE TRIGGER zmerps_Item_costprice__update_history_tr ON [ITEM]
FOR UPDATE
AS
if update(ima_price)
insert into zmerps_Item_costprice_history
select NEWID(), -- unique id
GETDATE(), -- CURRENT_date
'PRICE_CHANGE', -- reason code
a.ima_itemid, -- item id
a.ima_price-- item price
FROM Inserted b inner join item a
on b.ima_recordid = a.IMA_RecordID