How do I update column with NULL values - sql-server

I have two tables
Tb1
ID Name Birthdate
--------------------
1 Ball NULL
2 Tire 2022-01-01
3 Ball 1900-01-01
Tb2
ID Name Birthdate
------------------------
NULL Ball NULL
NULL Tire 2022-01-01
NULL Ball 1900-01-01
I want to update Tb2.ID to follow Tb1.ID, so here is my script
UPDATE Tb2.ID = Tb1.ID
FROM Tb2
LEFT JOIN Tb1 ON Tb2.Name = Tb1.Name
AND ISNULL (Tb2.Birthdate, '') = ISNULL (Tb1.Birthdate, '')
WHERE Tb2.ID IS NULL
And the result is ID 1 has 2 rows in Tb2 as seen like this table
ID
Name
Birthdate
1
Ball
NULL
2
Tire
2022-01-01
1
Ball
1900-01-01
My expectation is ID 3 is updated to Tb2 for this record
ID Name Birthdate
----------------------
3 Ball 1900-01-01
Can you guys help?
I suspect in the script goes wrong in join condition for Birthdate.
Thanks in advance

Try:
UPDATE Tb2
SET Tb2.ID = Tb1.ID
FROM Tb2
LEFT JOIN Tb1
ON Tb2.Name = Tb1.Name
AND ISNULL(Tb2.Birthdate,'9999-12-31') = ISNULL(Tb1.Birthdate,'9999-12-31')
WHERE Tb2.ID IS NULL
I think the empty strings convert to 1900-01-01 in your ISNULLs, using an invalid (but not 1900-01-01) date for NULL birth dates would address that.

If you are using SQL Server 2022 (or later), you can also use the new IS [NOT] DISTINCT FROM syntax. This allows for comparing both null and non-null values.
UPDATE Tb2
SET ID = Tb1.ID
FROM Tb2
JOIN Tb1
ON Tb2.Name = Tb1.Name
AND Tb2.Birthdate IS NOT DISTINCT FROM Tb1.Birthdate
WHERE Tb2.ID IS NULL
Note that there is no need for a left join, since you really only want to update when you have a match. Use an inner join instead.
See also this db<>fiddle for a quick DISTINCT FROM demo.

Related

SQL Server : selecting the Max Date/time of 2 rows that have the same value in the same column

Date Id Name ClockinOrOut
-------------------------------------------------
2019-12-19 10:24:00.000 4 Bob In
2019-12-19 15:26:10.000 4 Bob Out
2019-12-19 12:17:36.000 800 Gary In
2019-12-19 08:41:21.000 800 Gary Out
I can't seem to get this output with the most recent date/time based off of Id and doesn't matter whether the ClockInOrOut is In or Out, even with using the MAX() function
Date Id Name ClockinOrOut
-------------------------------------------------
2019-12-19 15:26:10.000 4 Bob Out
2019-12-19 12:17:36.000 800 Gary In
If you want the most recent row for each id, then a convenient method is:
select t.*
from t
where t.date = (select max(t2.date)
from t t2
where t2.id = t.id
);
With an index on (id, date), this is likely to have very good performance.
Here is a solution without subquery or aggregators
SELECT
*
FROM
tracking t
LEFT JOIN tracking t2
ON t2.id = t.id
AND t2.date > t.date
WHERE t2.id is null
Here we use a left join to the same table by ID (if you want you can use more fields) and
demand that the date be greater than that of t.
the row that cannot match this, is the biggest date of that id so we use the where t2.id is null to only show the not matching rows
NOTE: if the biggest date is more that once for the same ID this query will bring all those rows.If u have a autoincremental id you can use that for the last one inserted
changing AND t.date > t2.date for AND t.autoincremental_id > t2.autoincremental_id

do i need a certain join statement for my code

I'm stuck on writing this piece of code.
the output that i need to get is
firstName lastname Name Price Date
--------------- --------------- ------------------------- -------- ----------
Bateman Michael Furniture DR 222.80 2013-05-01
Tara Roswell Clothes Ladies 24.25 2013-05-04
LeMay Mike Toys Child 12.00 2013-05-12
Create a query that will show who picked up unsold items during the month of May 2013. Include in your output the first and last name of the owner, along with the name of the item, max price and pick up date. Order your output by Pick up date. My output looked like the following:
and my output is
FirstName LastName Name Price Date
--------------- --------------- ------------------------- ------- ----------
my code is
SELECT P.FirstName
, P.LastName
, IT.Name
, I.MaxPrice AS Price
, IP.Date
FROM People P
JOIN CHARITY C ON P.PeopleID = C.ContactID
JOIN Donation D ON C.CHARITYID = D.CHARITYID
JOIN Item_Donation ID ON D.DonationID = ID.DonationID
JOIN IteM I ON ID.ItemID = I.ItemID
JOIN Item_Type IT ON I.ItemTypeID = IT.ItemTypeID
JOIN Item_PickUp IP ON I.ItemID = IP.ItemID
ORDER BY IP.Date
I see nothing wrong with your query, so I suspect a data issue. Here is how I would investigate this. Start with querying the "root" table:
SELECT * FROM People p
If the results are not what you expect, then you have found the issue in your data.
If the results are ok, then add the first join:
SELECT *
FROM People P
JOIN CHARITY C ON P.PeopleID = C.ContactID
Same thing, if the results are not what you expect, then you have a data issue in the CHARITY table. Query the CHARITY table by itself to see why the rows from that table are not joining to People:
SELECT * FROM CHARITY
If the results are what you expect, then add the next JOIN, and continue, one JOIN at a time, until you find the one that causes no rows to be returned. Examine the data in that table to see why it doesn't join to your query before the join.

SQL merge rows with same ID to one

Currently I have the following table:
ID Date Number
-------------------------------------------------------
F78D56A2-5BF1-4172-90BA-23CAF6A05A10 NULL NULL
F78D56A2-5BF1-4172-90BA-23CAF6A05A10 NULL NULL
F78D56A2-5BF1-4172-90BA-23CAF6A05A10 NULL 001234
F78D56A2-5BF1-4172-90BA-23CAF6A05A10 2018-11-30 NULL
The requested output is:
ID Date Number
-------------------------------------------------------
F78D56A2-5BF1-4172-90BA-23CAF6A05A10 2018-11-30 001234
Ofcourse you cant use group by since that requires more arguments. How could I do this?
You may try JOIN to avoid GROUP BY
SELECT T1.Id, MAX(T1.Date) AS Date, MAX(T1.Number) As Number
FROM YourTableName AS T1
JOIN YourTableName AS T2 ON T1.column_name = T2.column_name;

How to query a Master database using Inner Join links to 2 sub-databases that are identical to each other

I have an Inventory table containing Master file info and 2 Movement History tables (Current Year and Last Year).
I want to use a Query to extract Movements from (say) June LAST Year to March THIS Year in Code, Date sequence.
I am relatively new to SQL and have tried to use the following INNER JOIN structure to do this:
SELECT Code, Descrip, Category, MLast.Date, MLast.DocNo, MCurr.Date, MCurr.DocNo
FROM Stock AS S
INNER JOIN MoveTrnArc MLast ON MLast.Stockcode = S.Code
AND MLast.Date >='2011/06/01' AND MLast.Date <='2012/03/31'
INNER JOIN MoveTrn MCurr ON MCurr.Stockcode = S.Code
AND MCurr.Date >='2011/06/01' AND MCurr.Date <='2012/03/31'
ORDER BY S.Code
This creates a Query Table with the following column structure:
Code | Descrip | Category | Date | DocNo | Date | DocNo |
...where the data from the LAST Year table appears in the first Date/DocNo columns and the CURRENT Year data appears in the second Date/DocNo columns.
What must I do to the Query to have each Movement in its own row or is there a better, more efficient Query to achieve this?
Also, I need the Movements listed in Code followed by Date sequence.
use union all instead of joins
select s.Code , s.Descrip , s.Category , t.Date , t.DocNo
from
(
select Stockcode, Date, DocNo from MoveTrnArc
union all
select Stockcode, Date, DocNo from MoveTrn
) t join Stock s on s.Code = t.Stockcode
where t.Date >='2011/06/01' AND t.Date <='2012/03/31'
beside careful with comparing dates, if Date column is type datetime and includes time you have to change t.Date <='2012/03/31' into t.Date <'2012/04/01' to include all the rows from 31st of march,
as '2012/03/31' is casted as '2012/03/31 00:00:00.000'

How to Get current column value, Previous Column Value

How to get Previous Column Value?
IIf id1 = id2 then display previous column id1 value
id1 id2
1001 1001
1002 1002
1003 1003
so on...
select id1, id2, Iff id2 = id1 then disply previous id1 value as idadjusted
Output
id1 id2 id3(Expected)
1001 1001 **1000**
1002 1002 **1001**
1003 1003 **1002**
so on...
I want to disply previous column value of id1
My query
SELECT CARDNO, NAME, TITLENAME, CARDEVENTDATE, MIN(CARDEVENTTIME) AS INTIME, MAX(CARDEVENTTIME) AS OUTTIME,
CARDEVENTDATE AS LASTDATE, MAX(CARDEVENTTIME) AS LASTTIME
FROM (SELECT T_PERSON.CARDNO, T_PERSON.NAME, T_TITLE.TITLENAME, T_CARDEVENT.CARDEVENTDATE, T_CARDEVENT.CARDEVENTTIME FROM (T_TITLE INNER JOIN T_PERSON ON T_TITLE.TITLECODE = T_PERSON.TITLECODE) INNER JOIN T_CARDEVENT ON T_PERSON.PERSONID = T_CARDEVENT.PERSONID ORDER BY T_PERSON.TITLECODE) GROUP BY CARDNO, NAME, TITLENAME, CARDEVENTDATE
For the LastDate - I want to Display Previous column cardeventdate value
For the Lasttime - I want to display previous column outtime value
Need Query Help?
The on clause is used to retrieve the previous id, I have tested it and works fine.
This solution will work even if intermediate ids are missiing i.e. ids are not consecutive
select t1.id, t1.column1, t1.column2,
case
when (t1.column1 = t1.column2) then t2.column1
else null
end as column3
from mytable t1
left outer join mytable t2
on t1.id = (select max(id) from mytable where id < t1.id)
For your complex query, you can create a view and then use the above sql format for your view:
Create a view MyView for:
SELECT CARDNO, NAME, TITLENAME, CARDEVENTDATE, MIN(CARDEVENTTIME) AS INTIME, MAX(CARDEVENTTIME) AS OUTTIME
FROM (SELECT T_PERSON.CARDNO, T_PERSON.NAME, T_TITLE.TITLENAME, T_CARDEVENT.CARDEVENTDATE, T_CARDEVENT.CARDEVENTTIME
FROM T_TITLE
INNER JOIN T_PERSON ON T_TITLE.TITLECODE = T_PERSON.TITLECODE
INNER JOIN T_CARDEVENT ON T_PERSON.PERSONID = T_CARDEVENT.PERSONID
ORDER BY T_PERSON.TITLECODE) GROUP BY CARDNO, NAME, TITLENAME, CARDEVENTDATE
And then the query would be:
select v1.CARDNO, v1.NAME, v1.TITLENAME, v1.CARDEVENTDATE, v1.INTIME, v1.OUTTIME,
case
when (v1.NAME = v1.TITLENAME) then v2.CARDEVENTDATE -- Replace v1.NAME = v1.TITLENAME with your reqd condn
else null end as LASTDATE,
case
when (v1.NAME = v1.TITLENAME) then v2.OUTTIME -- Replace v1.NAME = v1.TITLENAME with your reqd condn
else null end as LASTTIME
from myview v1
left outer join myview v2
on v2.CARDNO = (select max(CARDNO) from table1 where CARDNO < v1.CARDNO)
The v1.NAME = v1.TITLENAME in case stmt needs to be replaced with appropriate condn. I was not sure of the condn as its not mentioned in the question.
When you are designing your database you should consider the fact that you cannot rely on all the rows being in the right order. Instead you should create an identity value, that increment by one for every new row. And if you do this your solution becomes easy (or easier at least)
Assuming a new column called ID
SELECT colum1 FROM myTable WHERE ID = (SELECT ID FROM myTAble WHERE Column1 = Column2) - 1
If you get no match you will end up with ID -1 and this does not exist so you're ok.
If it is possible to get more than one match you will have to consider that too
Your table isn't in first normal form (1NF):
According to Date's definition of 1NF,
a table is in 1NF if and only if it is
'isomorphic to some relation', which
means, specifically, that it satisfies
the following five conditions:
1) There's no top-to-bottom ordering to the rows.
2) There's no left-to-right ordering to the columns.
3) ...

Resources