SQL merge rows with same ID to one - sql-server

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;

Related

How do I update column with NULL values

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.

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

How to select date and previous date

I have a table of referral records with a start date and end date. If the person has had previous referrals I need to retrieve the start and end date of the referral previous to the current one.
Any ideas would be greatly appreciated!
Example of what I hope to achieve
Per ID Ref ID Refrl_Start_D Refrl_End_D Prev_Refrl_S Prev_Refrl_S
1 5 10/10/2018 Null 01/02/2018 03/03/2018
2 4 05/04/2018 Null 01/01/2017 01/03/2017
1 3 01/02/2018 03/03/2018 02/01/2017 20/01/2017
1 2 02/01/2018 20/01/2018 Null Null
2 1 01/01/2018 01/03/2018 Null Null
Is have tried adding a Rank calc grouped by person. My plan was to create another table offset it by 1 and join them (i.e. Join referral 5 with 4). However I couldn't figure out how to get the join right.
SELECT DIM_PERSON_ID,
FACT_REFERRAL_ID,
REFRL_START_DTTM,
REFRL_END_DTTM
FROM FACT_REFERRALS;
You can use LAG here
SELECT DIM_PERSON_ID,
FACT_REFERRAL_ID,
REFRL_START_DTTM,
REFRL_END_DTTM
PrevStart = LAG(REFRL_START_DTTM)
OVER(PARTITION BY DIM_PERSON_ID
ORDER BY REFRL_START_DTTM DESC),
PrevEnd = LAG(REFRL_END_DTTM)
OVER(PARTITION BY DIM_PERSON_ID
ORDER BY REFRL_END_DTTMDESC)
FROM FACT_REFERRALS R;
You should be able to construct this with a CTE to calculate a rank/row number for each record based on the referral dates, then join the CTE to itself to get the previous referral. E.g:
WITH RANKED_REFERRALS AS (
SELECT DIM_PERSON_ID,
FACT_REFERRAL_ID,
REFRL_START_DTTM,
REFRL_END_DTTM,
ROW_NUMBER() OVER(PARTITION BY DIM_PERSON_ID ORDER BY REFRL_START_DATE) AS ROWNUM
FROM FACT_REFERRALS
)
SELECT A.DIM_PERSON_ID,
A.ACT_REFERRAL_ID,
A.REFRL_START_DTTM,
A.REFRL_END_DTTM,
B.REFRL_START_DTTM,
B.REFRL_END_DTTM
FROM RANKED_REFERRALS A
LEFT JOIN RANKED_REFERRALS B ON B.DIM_PERSON_ID = A.DIM_PERSON_ID AND B.ROWNUM = A.ROWNUM - 1

How to arrange data in sql server table

I tried many query to achieve the expected result , I couldn't find any solution.
Actual:-
ID | EmpDailyFee | EmpMonthlyFee | CompDailyFee | CompMnthlyFee
1 NULL 12 NULL NULL
1 50 NULL NULL NULL
1 60 NULL NULL NULL
2 50 NULL NULL NULL
3 NULL 30 NULL NULL
Expected :-
ID | EmpDailyFee | EmpMonthlyFee | CompDailyFee | CompMnthlyFee
1 50 12 NULL NULL
1 60 12 NULL NULL
2 50 NULL NULL NULL
3 NULL 30 NULL NULL
This looks like a table smell to me since the rows are sharing the same ID value but with different EmpDailyFee/EmpMonthlyFee values. But in this particular case you can get your expected output like this:
SELECT t1.ID, t1.EmpDailyFee, t2.EmpMonthlyFee
FROM #Test t1
INNER JOIN #Test t2 ON t1.ID = t2.ID
WHERE t1.EmpDailyFee IS NOT NULL AND t2.EmpMonthlyFee IS NOT NULL
UNION ALL
SELECT t1.ID, t1.EmpDailyFee, t1.EmpMonthlyFee
FROM #Test t1
WHERE (t1.EmpDailyFee IS NOT NULL OR t1.EmpMonthlyFee IS NOT NULL) AND t1.ID NOT IN
(
SELECT t3.ID
FROM #Test t3
INNER JOIN #Test t2 ON t3.ID = t2.ID
WHERE t3.EmpDailyFee IS NOT NULL AND t2.EmpMonthlyFee IS NOT NULL
)
This has been tested on SQL Fiddle
Note: The reason why I did not include CompDailyFee and CompMnthlyFee is because the values of both the actual and expected results were NULL. I am trying to write a "simple-as-possible" query based on what OP has provided.
If you're trying to insert or update data this could be the solution, customizing it on your needings
IF EXISTS (SELECT 1 FROM Employee WHERE ID = 1)
UPDATE Employee SET EmpMonthlyFee= #Value WHERE ID = 1
ELSE
INSERT Employee(ID,EmpDailyFee,EmpMonthlyFee,CompDailyFee,CompMnthlyFee)
VALUES(1,NULL,#value,NULL,NULL)
declare #t table (ID int,Empfee int,monthlyfee int,compdailyfee int,Cmpnymonthlyfee int)
insert into #t (ID,Empfee,monthlyfee,compdailyfee,Cmpnymonthlyfee)
values (1,NULL,12,NULL,NULL),
(1,50,NULL,NULL,NULL),
(1,60,NULL,NULL,NULL)
;with cte as (
select t.ID,t.Empfee,
tt.monthlyfee,
t.compdailyfee,
t.Cmpnymonthlyfee,
ROW_NUMBER()OVER(PARTITION BY t.ID,tt.monthlyfee ORDER BY t.ID,tt.monthlyfee)RN
from #t t
CROSS APPLY #t tt
where t.Empfee IS NULL OR tt.monthlyfee IS NOT NULL)
select C.ID,
C.Empfee,
C.monthlyfee,
C.compdailyfee,
C.Cmpnymonthlyfee from cte c
where c.Empfee IS NOT NULL AND c.monthlyfee IS NOT NULL
Can be done using COALESCE as well.
SELECT T1.ID,
T2.EmpDailyFee,
COALESCE(T1.EmpMonthlyFee , T2.EmpMonthlyFee) EmpMonthlyFee,
COALESCE(T1.CompDailyFee , T2.CompDailyFee) CompDailyFee ,
COALESCE(T1.CompMnthlyFee , T2.CompMnthlyFee) CompMnthlyFee
FROM
(SELECT * FROM Tab WHERE EmpDailyFee IS NULL)T1
JOIN
(SELECT * FROM Tab WHERE EmpDailyFee IS NOT NULL)T2
ON T1.ID = T2.ID
I have gone one step ahead and assumed that values from the first row will take priority if not null(As for the 3rd column in OP). This part can be neglected if not required.

SQL Pulling the latest information and information from another table

I have a record table that is recording changes within a table. I can pull the data from the first table fine, however when i try to join in another table to add some of its column information it stops displaying the information.
PartNumber | PartDesc | value | date
1 | test | 1 | 3/4/2015
I wanted to include the Aisle tag's from the location table
PartNumber| AisleTag | AisleTagTwo
1 | A1 | N/A
here is what i have as my sql statement so far
Select t1.PartNumber, t1.PartDesc , t1.NewValue , t1.Date,t2.AisleTag,t2.AisleTagTwo
from InvRecord t1
JOIN PartAisleListTbl t2 ON t1.PartNumber = t2.PartNumber
where Date = (select max(Date) from InvRecord where t1.PartNumber = InvRecord.PartNumber)
order by t1.PartNumber
it is coming up blank, my original sql statement doesn't include anything from t2. I am not sure what approach to go with in terms of getting the data combined any help is much appreciated thank you !
this should be the end result
PartNumber | PartDesc | value | date | AisleTag | AisleTagTwo
1 | test | 1 | 3/4/2015 | A1 | N/A
Pull the most recent row (based on Date) for each PartNumber in Table A and append data from Table B (joined on PartNumber):
SELECT *
FROM (
SELECT A.PartNumber
, A.PartDesc
, A.NewValue
, A.Date
, B.AisleTag
, B.AisleTagTwo
, DateSeq = ROW_NUMBER() OVER(PARTITION BY A.PartNumber ORDER BY A.Date DESC)
FROM InvRecord A
LEFT JOIN PartAisleListTbl B
ON A.PartNumber = B.PartNumber
) A
WHERE A.DateSeq = 1
ORDER BY A.PartNumber
Are you returning no records at all, or only records with AisleTag and AisleTagTwo as null?
Your sentence "it is coming up blank, my original sql statement doesn't include anything from t2." makes it sound like you're getting records with nulls for the t2 fields.
If you are, then you probably have a record in t2 that has nulls for those fields.
For troubleshooting purposes, try running the query without the WHERE clause:
Select t1.PartNumber, t1.PartDesc , t1.NewValue , t1.Date,t2.AisleTag,t2.AisleTagTwo
from InvRecord t1
JOIN PartAisleListTbl t2 ON t1.PartNumber = t2.PartNumber
order by t1.PartNumber
If you do get records, your problem is with the WHERE clause. If you don't, your problem is with the PartNumber fields in InvRecord and PartAisleListTbl not matching.
Not sure why your's isn't working... is date in both t1 and t2 by any chance?
Here's it re factored to use a inline view instead of a correlated query wonder if it makes a difference.
Select t1.PartNumber, t1.PartDesc , t1.NewValue , t1.Date,t2.AisleTag,t2.AisleTagTwo
from InvRecord t1
JOIN PartAisleListTbl t2
ON t1.PartNumber = t2.PartNumber
JOIN (select max(Date) mdate, PartNumber from InvRecord GROUP BY PartNumber) t3
on t3.partNumber= T1.PartNumber
and T3.mdate = T1.Date
order by t1.PartNumber

Resources