How to insert master detail records in T-SQL? - sql-server

I need to copy some master-detail records, along the lines of:
INSERT INTO Order
(
SupplierId
,DateOrdered
)
SELECT
SupplierID
,DateOrdered
FROM Order
WHERE SupplierId = 10
DECLARE #OrderId int;
Select #OrderId = Scope_Identity;
INSERT INTO OrderItem
(
Quantity
,ProductCode
,Price
,FkOrderId
)
SELECT
Quantity
,ProductCode
,Price
,FkOrderId
FROM OrderItem
WHERE FkOrderId = #OrderId
This will not work. The reason is that there are multiple Orders for Supplier = 10. So what is the best way to iterate through each Order where Supplier = 10, Add the order, and then add the relevant child OrderItem BEFORE going onto the next Order Record where supplier=10. I think I am talking about batching, possibly cursors, but I am a newbie to T-SQL / Store Procedures.
I would appreciate advice on the above.
Thanks.
EDIT
Some more information which I hope will clarify by virtue of some sample data.
Original Order Table
Id SupplierId DateOrdered
1 10 01/01/2000
2 10 01/01/2000
Original OrderItem Table
Id Quantity ProductCode Price FkOrderId
1 20 X1 100 1
2 10 Y1 50 1
3 30 X1 100 2
4 20 Y1 50 2
Final Order Table
Id SupplierId DateOrdered
1 10 01/01/2000
2 10 01/01/2000
3 10 01/01/2000 (Clone of 1)
4 10 01/01/2000 (Clone of 2)
Final OrderItem Table
Id Quantity ProductCode Price FkOrderId
1 20 X1 100 1
2 10 Y1 50 1
3 30 X1 100 2
4 20 Y1 50 2
5 20 X1 100 3 (Clone of 1, linked to clone Order=3)
6 10 Y1 50 3 (Clone of 2, linked to clone Order=3)
7 30 X1 100 4 (Clone of 3, linked to clone Order=4)
8 20 Y1 50 5 (Clone of 4, linked to clone Order=4)
So I need some help with the code can do this cloning of Order and OrderItem to achieve the "final" table records.
It seems I need to do something like:
For each matching record in "Order"
Clone Order Record
Clone OrderItem Record where FkOrderId = OldOrderId
Next

This answers your question (no cursors either)
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE [Order]
(
Id Int Primary Key Identity,
SupplierId Int,
DateOrdered Date
)
SET IDENTITY_INSERT [Order] ON
INSERT INTO [Order] (Id, SupplierId, DateOrdered)
VALUES
(1, 10, '01/01/2000'),
(2, 10, '01/01/2000')
SET IDENTITY_INSERT [Order] OFF
CREATE TABLE [OrderItem]
(
ID INT Primary Key Identity,
Quantity Int,
ProductCode CHAR(2),
Price Int,
FKOrderId Int
)
SET IDENTITY_INSERT [OrderItem] ON
INSERT INTO [OrderItem] (Id, Quantity, ProductCode, Price, FKOrderId)
VALUES
(1, 20, 'X1', 100, 1),
(2, 10, 'Y1', 50, 1),
(3, 30, 'X1', 100, 2),
(4, 20, 'Y1', 50, 2)
SET IDENTITY_INSERT [OrderItem] OFF
Query 1:
DECLARE #NewEntries TABLE (ID Int, OldId Int);
MERGE INTO [Order]
USING [Order] AS cf
ON 1 = 0 -- Ensure never match - therefore an Insert
WHEN NOT MATCHED AND cf.SupplierId = 10 THEN
INSERT(SupplierId, DateOrdered) Values(cf.SupplierId, cf.DateOrdered)
Output inserted.Id, cf.Id INTO
#NewEntries(Id, OldId);
INSERT INTO [OrderItem]
(
Quantity
,ProductCode
,Price
,FkOrderId
)
SELECT
Quantity
,ProductCode
,Price
,NE.ID
FROM [OrderItem] OI
INNER JOIN #NewEntries NE
ON OI.FKOrderId = NE.OldId ;
SELECT *
FROM [OrderItem];
Results:
| ID | QUANTITY | PRODUCTCODE | PRICE | FKORDERID |
|----|----------|-------------|-------|-----------|
| 1 | 20 | X1 | 100 | 1 |
| 2 | 10 | Y1 | 50 | 1 |
| 3 | 30 | X1 | 100 | 2 |
| 4 | 20 | Y1 | 50 | 2 |
| 5 | 20 | X1 | 100 | 3 |
| 6 | 10 | Y1 | 50 | 3 |
| 7 | 30 | X1 | 100 | 4 |
| 8 | 20 | Y1 | 50 | 4 |

Add an additional column to the Order table called OriginalOrderId. Make it nullable, FK'd back to OrderId, and put an index on it. Use "INSERT INTO [Order]... SELECT ... OUTPUT INSERTED.* INTO #ClonedOrders From ...". Add an index on #ClonedOrders.OriginalOrderId. Then you can do "INSERT INTO OrderItem ... SELECT co.OrderId, ... FROM #ClonedOrders co INNER JOIN OrderItem oi ON oi.OrderId = co.OriginalOrderId". This will get you the functionality that you're looking for, along with the performance benefits of set based statements. It will also leave you evidence of the original source of the orders and a field that you can use to differentiate cloned orders from non-cloned orders.

in this case you have to use output clause.. let me give you one sample script that will help you to relate with your requirement
Declare #Order AS Table(id int identity(1,1),SupplierID INT)
DECLARE #outputOrder AS TABLE
(Orderid INT)
INSERT INTO #Order (SupplierID)
Output inserted.id into #outputOrder
Values (102),(202),(303)
select * from #outputOrder
next step for your case would be use newly generated orderid from outputorder table & join to get orderitems from input table

This will handle your first table.
PS: Supply your questions in this state and they will be answered faster.
IF OBJECT_ID('Orders') IS NOT NULL DROP TABLE Orders
IF OBJECT_ID('OrderItem') IS NOT NULL DROP TABLE OrderItem
IF OBJECT_ID('tempdb..#FinalOrders') IS NOT NULL DROP TABLE #FinalOrders
CREATE TABLE Orders (OrdersID INT, SupplierID INT, DateOrdered DATETIME)
CREATE TABLE OrderItem (OrderItemID INT, Quantity INT, FkOrderId INT)
INSERT INTO Orders VALUES (1,20,'01/01/2000'),(2,20,'01/01/2000')
INSERT INTO OrderItem VALUES
(1,20,1),
(2,10,1),
(3,30,2),
(4,20,2)
SELECT
a.OrderItemID,
b.SupplierID,
b.DateOrdered
INTO #FinalOrders
FROM OrderItem as a
INNER JOIN Orders as b
ON a.FkOrderId = b.OrdersID
SELECT * FROM #FinalOrders

This can be achieved with a cursor. But please note that cursors will pose significant performance drawbacks.
DECLARE #SupplierID AS INT
DECLARE #OrderId AS INT
DECLARE #DateOrdered AS DATE
DECLARE #OrderIdNew AS INT
Declare #Order AS Table(OrderId INT,SupplierID INT,DateOrdered Date)
INSERT INTO #Order
SELECT
ID
,SupplierID
,DateOrdered
FROM [Order]
WHERE SupplierId = 10
DECLARE CUR CURSOR FAST_FORWARD FOR
SELECT
OrderId
,SupplierID
,DateOrdered
FROM #Order
OPEN CUR
FETCH NEXT FROM CUR INTO #OrderId, #SupplierID, #DateOrdered
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO [Order]
(
SupplierId
,DateOrdered
)
VALUES
(#SupplierID,#DateOrdered)
Select #OrderIdNew=##IDENTITY
INSERT INTO [OrderItem]
([Quantity]
,[ProductCode]
,[Price]
,[FkOrderId])
SELECT [Quantity]
,[ProductCode]
,[Price]
,#OrderIdNew
FROM [OrderItem]
WHERE [FkOrderId]=#OrderId
FETCH NEXT FROM CUR INTO #OrderId, #SupplierID, #DateOrdered
END
CLOSE CUR;
DEALLOCATE CUR;

You could try doing and inner join between Order and OrderItems where the clause of the inner join is SupplierId = 10,
or just modify your where to achieve the same result.
Try doing something along the lines of:
INSERT INTO OrderItem
(
Quantity
,ProductCode
,Price
,FkOrderId
)
SELECT
Quantity
,ProductCode
,Price
,FkOrderId
FROM OrderItem
where FkOrderId in (Select Id FROM Order WHERE SupplierId = 10)

Related

SQL Server : except with results from both datasets

I have the following tables:
Stores:
StoreID | Name
1 | Store1
2 | Store2
3 | Store3
EmID | StoreID
1 | 1
2 | 1
3 | 1
1 | 2
3 | 2
Employee:
EmID | Employee | Important
1 | Cashier | 1
2 | Manager | 1
3 | Guard | 0
I need a query to return StoreID and EmID where Employee is important (Important = 1) and the store and employee are not connected. Basically, the result should be:
StoreID | EmId
--------+-------
2 | 2
3 | 1
3 | 2
I have tried joins, outer joins / apply-es, except, cte, temporary tables, but still haven't found the answer.
Can someone help me with the code, or at least point me in the right direction?
Any idea will be very much appreciated.
Thanks.
You use a cross join to get the set of all possible employee/store combinations, and a left join to then remove the combinations that exist in the join table1:
declare #Stores table (StoreID int, Name char(6))
insert into #Stores (StoreID,Name) values
(1,'Store1'),
(2,'Store2'),
(3,'Store3')
declare #Employees table (EmID int, Employee varchar(8), Important bit)
insert into #Employees (EmID,Employee,Important) values
(1,'Cashier',1),
(2,'Manager',1),
(3,'Guard' ,0)
declare #Staffing table (EmID int, StoreID int)
insert into #Staffing (EmID,StoreID) values
(1,1),
(2,1),
(3,1),
(1,2),
(3,2)
select
*
from
#Stores s
cross join
#Employees e
left join
#Staffing st
on
s.StoreID = st.StoreID and
e.EmID = st.EmID
where
e.Important = 1 and
st.EmID is null
Results:
StoreID Name EmID Employee Important EmID StoreID
----------- ------ ----------- -------- --------- ----------- -----------
3 Store3 1 Cashier 1 NULL NULL
2 Store2 2 Manager 1 NULL NULL
3 Store3 2 Manager 1 NULL NULL
1The one I've named Staffing and you didn't name in the question. Note also (for future questions) that my presentation of the sample data takes up approximately as much space as yours in the question, provides the data types, and is a runnable script.
Please use Cross join followed by Left join and filter on IMP and StoreID null.
create table #Stores
(storeID int, Name varchar(100))
create table #ES
(empid int,storeID int)
create table #E
(eid int,employee varchar(100), imp int)
insert into #stores values(
1,'Store1'),
(2,'Store2'),
(3,'Store3')
insert into #ES values(
1,1),(2,1),(3,1),(1,2),(3,2)
insert into #E values
(1,'Cashier',1),
(2,'Manager', 1),
(3,'Guard',0)
select * from #Stores
select * from #ES
select * from #E
select #stores.storeid,#E.eid from #Stores
cross join #E
LEFT join #ES
on #ES.storeid = #Stores.storeid
and #E.eid = #ES.empid
where #E.imp = 1
and #ES.storeID is null
Try this query.
I assumed the table name of the "Employee" is dbo.Employee and table name of "Stores" is dbo.Stores and the intermediate table is "dbo.EmpStore"
SELECT S.StoreID, E.EmID
FROM dbo.Stores S
CROSS JOIN dbo.Employees E
LEFT JOIN dbo.EmpStore ES ON ES.EmID = E.EmID AND ES.StoreID = S.StoreID
WHERE E.Important=1 AND ES.EmID IS NULL

Insert multuple rows at once with a calculated column from prior inserts into SQL Server

I'm trying to figure out how to do a multi-row insert as one statement in SQL Server, but where one of the columns is a column computer based on the data as it stands after every insert row.
Let's say I run this simple query and get back 3 records:
SELECT *
FROM event_courses
WHERE event_id = 100
Results:
id | event_id | course_id | course_priority
---+----------+-----------+----------------
10 | 100 | 501 | 1
11 | 100 | 502 | 2
12 | 100 | 503 | 3
Now I want to insert 3 more records into this table, except I need to be able to calculate the priority for each record. The priority should be the count of all courses in this event. But if I run a sub-query, I get the same priority for all new courses:
INSERT INTO event_courses (event_id, course_id, course_priority)
VALUES (100, 500,
(SELECT COUNT (id) + 1 AS cnt_event_courses
FROM event_courses
WHERE event_id = 100)),
(100, 501,
(SELECT COUNT (id) + 1 AS cnt_event_courses
FROM event_courses
WHERE event_id = 1))
Results:
id | event_id | course_id | course_priority
---+----------+-----------+-----------------
10 | 100 | 501 | 1
11 | 100 | 502 | 2
12 | 100 | 503 | 3
13 | 100 | 504 | 4
14 | 100 | 505 | 4
15 | 100 | 506 | 4
Now I know I could easily do this in a loop outside of SQL and just run a bunch of insert statement, but that's not very efficient. There's got to be a way to calculate the priority on the fly during a multi-row insert.
Big thanks to #Sean Lange for the answer. I was able to simplify it even further for my application. Great lead! Learned 2 new syntax tricks today ;)
DECLARE #eventid int = 100
INSERT event_courses
SELECT #eventid AS event_id,
course_id,
course_priority = existingEventCourses.prioritySeed + ROW_NUMBER() OVER(ORDER BY tempid)
FROM (VALUES
(1, 501),
(2, 502),
(3, 503)
) courseInserts (tempid, course_id) -- This basically creates a temp table in memory at run-time
CROSS APPLY (
SELECT COUNT(id) AS prioritySeed
FROM event_courses
WHERE event_id = #eventid
) existingEventCourses
SELECT *
FROM event_courses
WHERE event_id = #eventid
Here is an example of how you might be able to do this. I have no idea where your new rows values are coming from so I just tossed them in a derived table. I doubt your final solution would look like this but it demonstrates how you can leverage ROW_NUMBER for accomplish this type of thing.
declare #EventCourse table
(
id int identity
, event_id int
, course_id int
, course_priority int
)
insert #EventCourse values
(100, 501, 1)
,(100, 502, 2)
,(100, 503, 3)
select *
from #EventCourse
insert #EventCourse
(
event_id
, course_id
, course_priority
)
select x.eventID
, x.coursePriority
, NewPriority = y.MaxPriority + ROW_NUMBER() over(partition by x.eventID order by x.coursePriority)
from
(
values(100, 504)
,(100, 505)
,(100, 506)
)x(eventID, coursePriority)
cross apply
(
select max(course_priority) as MaxPriority
from #EventCourse ec
where ec.event_id = x.eventID
) y
select *
from #EventCourse

Converting multiple rows into one in SQL Server

I have 2 tables:
Product:
ProductId | Name | Description
----------+-------+-------------------------------------
1 | shirt | this is description for shirt
2 | pent | this is description for pent
ProductOverride:
ProductOverrideId | ColumnId | Value | ProductId
------------------+-----------+------------------------+-----------
1 | 1 | overridden name | 1
2 | 2 | overridden description | 1
where ColumnId is column_id from sys.columns.
I want to select all the products with the following requirement:
if product name or product description is overridden in ProductOverride table, get the overridden value of name/description, otherwise get the name/description value from the product table.
Sample output:
ProductId | Name | Description
----------+-----------------+---------------------------
1 | overridden name | overridden description
2 | pent | this is description for pent
I have the following query which returns the exact result.
DECLARE #productNameColumnId INT = 1;
DECLARE #productDescriptionColumnId INT = 2;
WITH OverriddenProductNameCTE ([Value], [ProductId]) AS
(
SELECT
temp.[Value], temp.ProductId
FROM
ProductOverride temp
WHERE
temp.ColumnId = #productNameColumnId
), OverriddenProductDescriptionCTE ([Value], [ProductId]) AS
(
SELECT
temp.[Value], temp.ProductId
FROM
ProductOverride temp
WHERE
temp.ColumnId = #productDescriptionColumnId
)
SELECT
p.ProductId,
CASE
WHEN EXISTS(SELECT [Value]
FROM OverriddenProductNameCTE opnc
WHERE opnc.ProductId = p.ProductId)
THEN (SELECT [Value]
FROM OverriddenProductNameCTE opnc
WHERE opnc.ProductId = p.ProductId)
ELSE p.[Name]
END AS [Name],
CASE
WHEN EXISTS(SELECT [Value]
FROM OverriddenProductDescriptionCTE opdc
WHERE opdc.ProductId = p.ProductId)
THEN (SELECT [Value]
FROM OverriddenProductDescriptionCTE opdc
WHERE opdc.ProductId = p.ProductId)
ELSE p.[Description]
END AS [Description]
FROM
product p
but in the CASE statements, I have the following repetitive code:
SELECT [Value]
FROM OverriddenProductNameCTE opnc
WHERE opnc.ProductId = p.ProductId
which means if the CASE statement's first condition is true DBMS will execute the same query again in the THEN part.
I want to improve this query both in terms of simplifying the query and in terms of processing.
Also if there is any advantage of using CTEs in this situation?
If it's only 2 columns I think the simplest thing you can do is left join twice with coalesce:
SELECT p.ProductId
,COALESCE(poN.Value, p.Name) As Name
,COALESCE(poD.Value, p.Description) As Description
FROM Product p
LEFT JOIN ProductOverride poN ON p.ProductId = poN.ProductId AND poN.ColumnId = 1
LEFT JOIN ProductOverride poD ON p.ProductId = poD.ProductId AND poD.ColumnId = 2
If it's more columns I would suggest pivoting the ProductOverride table and left join to that - Like this (a complete example):
Create and populate sample tables (Please save us this step in your future questions)
CREATE TABLE Product
(
ProductId int,
Name varchar(100),
Description varchar(100),
price int null
);
INSERT INTO Product VALUES
(1, 'shirt', 'Description for shirts', 1),
(2, 'Pants', 'Description for pants', 4),
(3, 'Socks', 'Description for socks', 5)
CREATE TABLE ProductOverride
(
ProductOverrideId int,
ColumnId int,
Value varchar(100),
ProductId int
);
INSERT INTO ProductOverride VALUES
(1,1,'product 1 name',1),
(2,2,'product 1 desc',1),
(3,3,'7',1),
(4,1,'pants name',2),
--Note: no pants description in the override tabl
(6,3,'8',2);
-- Note: no socks at all in override table
The query:
SELECT p.ProductId
,COALESCE(override.[1], p.Name) As Name
,COALESCE(override.[2], p.Description) As Description
,COALESCE(CAST(override.[3] as int), p.Price) As Price
FROM Product p
LEFT JOIN
(
SELECT *
FROM
(
SELECT ProductId, Value, ColumnId -- Columns To use for pivot
FROM ProductOverride
) ColumnsToPivot
PIVOT (
max (Value)
for ColumnId in ([1], [2], [3]) -- Values in ColumnId column to make the column names
) as pivotedData
) as override ON p.ProductId = override.ProductId
Results:
ProductId Name Description Price
1 product 1 name product 1 desc 7
2 pants name Description for pants 8
3 Socks Description for socks 5
You can see a live demo on rextester.

SQL Server : Bulk insert a Datatable into 2 tables

Consider this datatable :
word wordCount documentId
---------- ------- ---------------
Ball 10 1
School 11 1
Car 4 1
Machine 3 1
House 1 2
Tree 5 2
Ball 4 2
I want to insert these data into two tables with this structure :
Table WordDictionary
(
Id int,
Word nvarchar(50),
DocumentId int
)
Table WordDetails
(
Id int,
WordId int,
WordCount int
)
FOREIGN KEY (WordId) REFERENCES WordDictionary(Id)
But because I have thousands of records in initial table, I have to do this just in one transaction (batch query) for example using bulk insert can help me doing this purpose.
But the question here is how I can separate this data into these two tables WordDictionary and WordDetails.
For more details :
Final result must be like this :
Table WordDictionary:
Id word
---------- -------
1 Ball
2 School
3 Car
4 Machine
5 House
6 Tree
and table WordDetails :
Id wordId WordCount DocumentId
---------- ------- ----------- ------------
1 1 10 1
2 2 11 1
3 3 4 1
4 4 3 1
5 5 1 2
6 6 5 2
7 1 4 2
Notice :
The words in the source can be duplicated so I must check word existence in table WordDictionary before any insert record in these tables and if a word is found in table WordDictionary, the just found Word ID must be inserted into table WordDetails (please see Word Ball)
Finally the 1 M$ problem is: this insertion must be done as fast as possible.
If you're looking to just load the table the first time without any updates to the table over time you could potentially do it this way (I'm assuming you've already created the tables you're loading into):
You can put all of the distinct words from the datatable into the WordDictionary table first:
SELECT DISTINCT word
INTO WordDictionary
FROM datatable;
Then after you populate your WordDictionary you can then use the ID values from it and the rest of the information from datatable to load your WordDetails table:
SELECT WD.Id as wordId, DT.wordCount as WordCount, DT.documentId AS DocumentId
INTO WordDetails
FROM datatable as DT
INNER JOIN WordDictionary AS WD ON WD.word = DT.word
There a little discrepancy between declared table schema and your example data, but it was solved:
1) Setup
-- this the table with the initial data
-- drop table DocumentWordData
create table DocumentWordData
(
Word NVARCHAR(50),
WordCount INT,
DocumentId INT
)
GO
-- these are result table with extra information (identity, primary key constraints, working foreign key definition)
-- drop table WordDictionary
create table WordDictionary
(
Id int IDENTITY(1, 1) CONSTRAINT PK_WordDictionary PRIMARY KEY,
Word nvarchar(50)
)
GO
-- drop table WordDetails
create table WordDetails
(
Id int IDENTITY(1, 1) CONSTRAINT PK_WordDetails PRIMARY KEY,
WordId int CONSTRAINT FK_WordDetails_Word REFERENCES WordDictionary,
WordCount int,
DocumentId int
)
GO
2) The actual script to put data in the last two tables
begin tran
-- this is to make sure that if anything in this block fails, then everything is automatically rolled back
set xact_abort on
-- the dictionary is obtained by considering all distinct words
insert into WordDictionary (Word)
select distinct Word
from DocumentWordData
-- details are generating from initial data joining the word dictionary to get word id
insert into WordDetails (WordId, WordCount, DocumentId)
SELECT W.Id, DWD.WordCount, DWD.DocumentId
FROM DocumentWordData DWD
JOIN WordDictionary W ON W.Word = DWD.Word
commit
-- just to test the results
select * from WordDictionary
select * from WordDetails
I expect this script to run very fast, if you do not have a very large number of records (millions at most).
This is the query. I'm using temp table to be able to test.
if you use the 2 CTEs, you'll be able to generate the final result
1.Setting up a sample data for test.
create table #original (word varchar(10), wordCount int, documentId int)
insert into #original values
('Ball', 10, 1),
('School', 11, 1),
('Car', 4, 1),
('Machine', 3, 1),
('House', 1, 2),
('Tree', 5, 2),
('Ball', 4, 2)
2. Use cte1 and cte2. In your real database, you need to replace #original with the actual table name you have all initial records.
;with cte1 as (
select ROW_NUMBER() over (order by word) Id, word
from #original
group by word
)
select * into #WordDictionary
from cte1
;with cte2 as (
select ROW_NUMBER() over (order by #original.word) Id, Id as wordId,
#original.word, #original.wordCount, #original.documentId
from #WordDictionary
inner join #original on #original.word = #WordDictionary.word
)
select * into #WordDetails
from cte2
select * from #WordDetails
This will be data in #WordDetails
+----+--------+---------+-----------+------------+
| Id | wordId | word | wordCount | documentId |
+----+--------+---------+-----------+------------+
| 1 | 1 | Ball | 10 | 1 |
| 2 | 1 | Ball | 4 | 2 |
| 3 | 2 | Car | 4 | 1 |
| 4 | 3 | House | 1 | 2 |
| 5 | 4 | Machine | 3 | 1 |
| 6 | 5 | School | 11 | 1 |
| 7 | 6 | Tree | 5 | 2 |
+----+--------+---------+-----------+------------+

How to retrieve unique records having unique values in two columns from a table in SQL Server

I want to query a table where I need the result that contains unique values from two columns together. For e.g.
Table
EnquiryId | EquipmentId | Price
-----------+--------------+-------
1 | E20 | 10
1 | E50 | 40
1 | E60 | 20
2 | E30 | 90
2 | E20 | 10
2 | E90 | 10
3 | E90 | 10
3 | E60 | 10
For each EnquiryId, EquipmentId will be unique in the table. Now I want a result where I can get something like this
EnquiryId | EquipmentId | Price
-----------+--------------+-------
1 | E20 | 10
2 | E30 | 90
3 | E90 | 10
In the result each enquiryId present in the table should be displayed uniquely.
If suppose I have 3 EquipmentIds "E20,E50,E60" for EnquiryId "1".. Any random EquipmentId should be displayed from these three values only.
Any help would be appreciated. Thank you in advance.
QUERY
;WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER
(PARTITION BY enquiryID
ORDER BY enquiryID ) AS RN
FROM tbl
)
SELECT enquiryID,equipmentID,Price
FROM cte
WHERE RN=1
FIND FIDDLE HERE
The following code must help you..
Sorry that I ended up in a lengthy solution only. Run it in your SSMS and see the result.
Declare #tab table (EnquiryId int, EquipmentId varchar(10),Price int)
Insert into #tab values
(1,'E20',10),
(1,'E50',40),
(1,'E60',20),
(2,'E30',90),
(2,'E20',10),
(2,'E90',10),
(3,'E90',10),
(3,'E60',10)
----------------------------------------------
Declare #s int = 1
Declare #e int,#z varchar(10)
Declare #Equipment table (EquipmentId varchar(10),ind int)
Insert into #Equipment (EquipmentId) Select Distinct EquipmentId From #tab
Declare #Enquiry table (id int identity(1,1),EnquiryId int,EquipmentId varchar(10))
Insert into #Enquiry (EnquiryId) Select Distinct EnquiryId From #tab
Set #e = ##ROWCOUNT
While #s <= #e
begin
Select Top 1 #z = T.EquipmentId
From #tab T
Join #Enquiry E On T.EnquiryId = E.EnquiryId
Join #Equipment Eq On Eq.EquipmentId = T.EquipmentId
Where E.id = #s
And Eq.ind is Null
Order by NEWID()
update #Enquiry
Set EquipmentId = #z
Where id = #s
update #Equipment
Set ind = 1
Where EquipmentId = #z
Set #s = #s + 1
End
Select T.EnquiryId,T.EquipmentId,T.Price
From #tab T
left join #Enquiry E on T.EnquiryId = E.EnquiryId
Where T.EquipmentId = E.EquipmentId
You can use GROUP BY (Typical way) to remove duplicate value.
Basic steps are:
Alter table & Add Identity Column.
Group by columns which can be dupicate.
Delete those record.
Check here Remove Duplicate Rows from a Table in SQL Server

Resources