SQL where clause for self-referencing table - sql-server

I have something like the following table:
CREATE TABLE [dbo].[Test]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Title] [nvarchar](450) NULL,
[Description] [nvarchar](4000) NULL,
[Created] [datetime] NULL,
[OrgId] [int] NULL CONSTRAINT [FK_Test_OrgId] FOREIGN KEY REFERENCES Test(Id),
CONSTRAINT [PK_Test]
PRIMARY KEY CLUSTERED ([Id] ASC)
)
A new entry has OrgId = null. If an entry has been edited, a new row is created with OrgId set to its original parent. If an entry is edited multiple times, all children will have OrgId set to the Id of the original row. The created datetime provides the "order".
What I need to do is select only the newest versions.
Given the table below, I am looking to select only Id 3, 5 & 6
Id Title Description Created PreId
-----------------------------------------------------
1 Car Orginal car 2014-01-01 NULL
2 House Original house 2014-01-01 NULL
3 Bike Original bike 2014-01-01 NULL
4 Car Car updated 2014-06-01 1
5 Car Car updated again 2014-08-01 1
6 House house updated 2014-09-01 2
Any input appreciated.
Thanks.

Since all records are pointing at the original row (and not the previous one) :
SELECT ID, Title, DEscription, CREATED, PreID
FROM
(SELECT ID, Title, DEscription, CREATED, PreID,
ROW_NUMBER() over(partition by ISNULL(OrgID,id) order by id desc) rn
FROM test) A
where RN = 1

WITH Titles AS
(
SELECT DISTINCT Title
FROM dbo.Test
)
SELECT A.ID, Ti.Title, A.[Description], A.Created, A.OrgId
FROM Titles AS Ti
OUTER APPLY (SELECT TOP (1) ID, [Description], [Created], [OrgId]
FROM dbo.Test AS Te
WHERE Te.Title = Ti.Title
ORDER BY Created DESC
) AS A;

Related

How to design a table having age which returns current age of that person when queried after two years in SQL Server?

I want to design a table as below, which returns the current age of a person when queried after two years.
CREATE TABLE Person
(
Person_ID INT IDENTITY(1,1) NOT NULL,
Initial VARCHAR(50) NULL,
Surname VARCHAR(100) NOT NULL,
Age INT NOT NULL
)
For example table has 2 rows
Person_ID Initial Surname Age
-------------------------------
1 AR Rahman 40
2 M Jackson 50
On a select query after two years
select age
from Person
where person_ID = 1
it should return 42
You should store date of birth in your table and always calculate age.
To achieve this you can use calculated column or you will need include calculations in the query itself.
Store date of birth in your table as DATE and use computed column without using persisted keyword because age calculation is non-deterministic as shown in the code below.
CREATE TABLE #Person
(
Person_ID INT IDENTITY(1,1) NOT NULL,
Initial VARCHAR(50) NULL,
Surname VARCHAR(100) NOT NULL,
DOB DATE NULL,
Age AS DATEDIFF(YEAR,DOB,getdate())
)
INSERT INTO #Person
SELECT 'Gyan','Prakash','26-feb-1994'
SELECT * FROM #Person

Script to update thousands of SQL records with a unique ID

I've got a table named 'users' with 5800 records where the externalID is NULL. I want to add an unique externalID to each of these records in the following format: 'legacy_N' where N is some number between 1 and 5800.
this:
ID externalID Name AddedUTC
123 John 2019-09-19 15:14:11.837
634 Susan 2019-09-18 20:39:38.247
499 Lolita 2019-09-18 19:58:29.320
...
becomes this:
ID externalID Name AddedUTC
123 legacy_1 John 2019-09-19 15:14:11.837
634 legacy_2 Susan 2019-09-18 20:39:38.247
499 legacy_3 Lolita 2019-09-18 19:58:29.320
...
Anyway I can do this programatically? Or am I about to spend the 8 hours updating these one by one?
Here's an example based on the data in your question:
-- Create a test table with test data in it
CREATE TABLE TestData([ID] int, [externalID] varchar(20), [Name] varchar(50), [AddedUTC] datetime);
INSERT INTO TestData ([ID], [externalID], [Name], [AddedUTC])
VALUES (123, NULL, 'John', '2019-09-19 15:14:11.837'),
(499, NULL, 'Lolita', '2019-09-18 19:58:29.320'),
(634, NULL, 'Susan', '2019-09-18 20:39:38.247');
-- Display the test data
SELECT * FROM TestData;
-- Do the update
WITH NumberedData AS (
SELECT ID, ROW_NUMBER() OVER (ORDER BY AddedUTC) AS RowNum
FROM TestData
)
UPDATE td
SET [externalID] = 'Legacy_' + CAST(RowNum AS varchar)
FROM TestData td
INNER JOIN NumberedData nd ON td.ID = nd.ID
-- Display updated data
SELECT * FROM TestData;
If you want to order by ID, then you can change the ROW_NUMBER clause to "OVER(ORDER BY ID)" instead.

Possible duplicates to find in SQL

I've been trying the following suggestions from this post, but this does not apply for my case or at least I am not capable of adapting the query to my needs.
I have three tables: one stands for documents header, one stands for documents lines and one stands for item's information (Code, Description etc).
I would like to extract all the documents number that have the same value (this is the information from the documents header table), the same items (the code of the item) and the same quantity (from the lines of the documents tables). How can I extract this information? Thanks
The tables are -
DocHeader DocLines Items
ID fDocID ID
Code fItemID Code
Date Quantity Description
---- -------- -----------
TotalValue etc etc
Later edit
Output should like something like:
DocCode ItemCode Quantity TotalValue
01 001 5 1000
01 002 5 1000
01 003 4 1000
02 001 5 1000
02 002 5 1000
02 003 4 1000
DDL
create table DocHeader
(
Id bigint not null identity(1,1) primary key clustered
, Code nvarchar(32) not null
, [Date] datetime not null
)
go
create table Items
(
Id bigint not null identity(1,1) primary key clustered
, Code nvarchar(32) not null
, [Description] nvarchar(256)
, UnitPrice money not null
)
go
create table DocLines
(
Id bigint not null identity(1,1) primary key clustered
,fDocId bigint not null constraint fk_DocLines_fDocId foreign key references DocHeader(Id)
,fItemId bigint not null constraint fk_DocLines_fDocId foreign key references Items(Id)
,Quantity int not null
)
go
create view vDocHeader as
select dh.*
, x.TotalValue
from DocHeader
left outer join
(
select dl.fDocId
, sum(dl.Quantity * i.UnitPrice) TotalValue
from DocLines dl
inner join Items i
on i.Id = dl.fItemId
group by dl.fDocId
) x
on x.fDocId = dh.Id
Why not simple grouping?
SELECT dh.Code AS DocCode, i.Code AS ItemCode, Quantity, SUM(dl.Quantity * i.UnitPrice) AS TotalValue
FROM DocHeader dh
LEFT JOIN DocLines dl ON dl.fDocId=dh.id
JOIN Items i ON i.Id = dl.fItemId
GROUP BY dh.Code,i.Code,Quantity

how to join 2 tables but have the same result count as table a

here is the dilemma i am having...
i have 2 tables
create table #orders
(orderNumber int,qty int,sku varchar(250),barcode varchar(250))
create table #allItemsInBox
([id] int,[date] date,[localsku] varchar(250),[box] varchar(250),barcode varchar(250))
i need to join the 2 tables on [barcode] and only have 1 result in the final table for every row in #allItemsInBox
please note [#allItemsInBox].[id] is unique the other fields in [#allItemsInBox] may not be
how would i go about doing something like this?
sample data:
[#orders]
(1,0,'10','10')
(1,0,'20','20')
(3,0,'20','20')
(4,0,'30','30')
(5,0,'40','40')
(6,0,'50','50')
#allItemsInBox
(1,'12/3/2014',10,'Box1',10)
(2,'12/2/2014',20,'Box2',20)
(3,'12/1/2014',20,'Box3',20)
(4,'11/30/2014',20,'Box4',20)
(5,'11/29/2014',30,'Box5',30)
(6,'11/28/2014',40,'Box6',40)
(7,'11/27/2014',60,'Box8',60)
(8,'11/27/2014',50,'Box10',50)
#output
(ordernumber int,uniqueitemID int,localsku varchar(250),box varchar(250))
(1,1,10,'Box1')
(1,2,20,'Box2')
(3,3,10,'Box3')
(4,5,30,'Box5')
(5,6,40,'Box6')
(6,8,50,'Box10')
This is quick but works. Depending on the size of your data this might be not the best way performance wise. But this will give you a start
DECLARE #orders TABLE (
orderNumber int,
qty int,
sku varchar(250),
barcode varchar(250)
)
DECLARE #allItemsInBox TABLE (
[id] int,
[date] date,
[localsku] varchar(250),
[box] varchar(250),
barcode varchar(250)
)
INSERT INTO #orders VALUES
(1,0,'10','10'),
(1,0,'20','20'),
(3,0,'20','20'),
(4,0,'30','30'),
(5,0,'40','40'),
(6,0,'50','50')
INSERT INTO #allItemsInBox VALUES
(1,'2014-12-03',10,'Box1',10),
(2,'2014-12-02',20,'Box2',20),
(3,'2014-12-01',20,'Box3',20),
(4,'2014-11-30',20,'Box4',20),
(5,'2014-11-29',30,'Box5',30),
(6,'2014-11-28',40,'Box6',40),
(7,'2014-11-27',60,'Box8',60),
(8,'2014-11-27',50,'Box10',50)
SELECT
orders.orderNumber AS ordernumber
,(SELECT TOP 1 allItems.id FROM #allItemsInBox allItems WHERE allItems.barcode = orders.barcode AND allItems.id >= orders.orderNumber ORDER BY allItems.id) AS uniqueitemID
,(SELECT TOP 1 allItems.localsku FROM #allItemsInBox allItems WHERE allItems.barcode = orders.barcode AND allItems.id >= orders.orderNumber ORDER BY allItems.id) AS localsku
,(SELECT TOP 1 allItems.box FROM #allItemsInBox allItems WHERE allItems.barcode = orders.barcode AND allItems.id >= orders.orderNumber ORDER BY allItems.id) AS box
FROM
#orders orders
Results in:
ordernumber uniqueitemID localsku box
1 1 10 Box1
1 2 20 Box2
3 3 20 Box3
4 5 30 Box5
5 6 40 Box6
6 8 50 Box10
edit: I updated the answer. You now have the same output as you specified in your example/question

SQL Server join query not retrieving proper result

Select the list of all dealers whose vehicles are never assigned to any customer i.e that vehicle is not present in PS3_VehicleBooking, and committed date is greater than today's date.
3 tables to be used are-
CREATE TABLE PS3_Dealer(
ID int IDENTITY(1,1) NOT NULL Primary KEY,
DealerID varchar(255) NULL,
DealerName varchar(255) NOT NULL,
ContactNo varchar(255) NOT NULL,
NoOfVehicles bigint NOT NULL,
CommittedDate date NOT NULL
);
create table PS3_Vehicle
(
ID int IDENTITY(1,1) NOT NULL Primary Key,
DealerID varchar(255) NOT NULL,
VehicleID varchar(255) UNIQUE NOT NULL,
VehicleName varchar(255) NOT NULL,
Capacity BIGINT NOT NULL
);
create table PS3_VehicleBooking
(
ID int IDENTITY(1,1) NOT NULL Primary Key,
BookingID varchar(255) NOT NULL UNIQUE,
VehicleID varchar(255) NOT NULL,
StartDate date NOT NULL,
EndDate date NOT NULL
);
PS3_Dealer values-
DealerID DealerName ContactNo NoOfVehicles CommittedDate
1 ng 9 5 2013-12-12
2 nikki 5 7 2013-12-25
3 nik 4 6 2013-10-11
4 hj 2 2 2014-11-10
5 pk 67 8 2013-10-10
PS3_Vehicle
DealerID VehicleID VehicleName Capacity
1 V1 ind 4
2 V2 innova 5
3 V3 innova 6
1 V4 ula 8
4 V5 hkk 2
5 V6 ghi 9
2 V7 bjhgi 4
PS3_VehicleBooking-
BookingID VehicleID StartDate EndDate
1 V1 2013-12-13 2013-12-17
2 V2 2013-10-11 2013-10-13
3 V3 2014-12-10 2014-12-13
4 V4 2012-10-10 2012-10-13
5 V2 2013-12-14 2013-12-18
expected outcome-
DealerID DealerName ContactNo NoOfVehicles CommittedDate
4 hj 2 2 2014-11-10
but i am getting-
DealerID DealerName ContactNo NoOfVehicles CommittedDate
4 hj 2 2 2014-11-10
2 Nikki 5 7 2013-12-25
i dont want dealer id 2 in result because V2 provided by dealer id 2 is present in PS3_Booking.
My query is-
SELECT h.DealerID,
h.DealerName,
h.ContactNo,
h.NoOfVehicles,
h.CommittedDate
FROM PS3_Dealer h
INNER JOIN(SELECT DealerID,
PS3_VehicleBooking.VehicleID
FROM PS3_Vehicle
LEFT JOIN PS3_VehicleBooking
ON PS3_Vehicle.VehicleID = PS3_VehicleBooking.VehicleID) w
ON h.DealerID = w.DealerID
WHERE w.VehicleID IS NULL
AND h.CommittedDate > GETDATE()
please correct where i am wrong?
The problem is that DealerID 2 has 2 Vehicles. One that has booking, and the other does not. When you run
SELECT DealerID,
PS3_VehicleBooking.VehicleID
FROM PS3_Vehicle
LEFT JOIN PS3_VehicleBooking
ON PS3_Vehicle.VehicleID = PS3_VehicleBooking.VehicleID
You will get one record that has DealerID 2 with NULL VehicleID and the other none NULL Vehicle ID.
You can try to the run the statement below to get the desired results (may not be the most optimal, but it is a fix to your statement):
SELECT h.DealerID,
h.DealerName,
h.ContactNo,
h.NoOfVehicles,
h.CommittedDate
FROM PS3_Dealer h
INNER JOIN(SELECT DealerID,
MAX(PS3_VehicleBooking.VehicleID) as VehicleID
FROM PS3_Vehicle
LEFT JOIN PS3_VehicleBooking
ON PS3_Vehicle.VehicleID = PS3_VehicleBooking.VehicleID
GROUP BY DealerID
) w
ON h.DealerID = w.DealerID
WHERE w.VehicleID IS NULL
AND h.CommittedDate > GETDATE()
Edited to actually answer the question
You were getting Nikki because there does exist a car for her (V7) that is not in the booking table.
This should exclude Nikki.
SELECT h.DealerID,
h.DealerName,
h.ContactNo,
h.NoOfVehicles,
h.CommittedDate
FROM PS3_Dealer d
WHERE NOT EXISTS
(SELECT *
FROM PS3_VehicleBookingb
JOIN PS3_Vehiclev ON b.vehicleID = v.VehicleID
JOIN PS3_Dealerd2 ON d2.dealerID = v.dealerID
WHERE d2.dealerID = d.dealerID)
AND CommittedDate > Current_date()
http://sqlfiddle.com/#!2/fb365/19

Resources