SQL Server 2005 Bulk insert on split string where not exists - sql

I have a problem with an insert statement where I cannot get the "where not exists" clause to work. I would prefer a solution where I do not have to dump my list into a declared a table. Here are two of the solutions I have tried, could someone please tell where my syntax is wrong? My split string list has three values, the first two values would be new, but the third value already exists in the database and so should not be inserted.
With this sample I get no data returned at all:
insert into dbo.Cook(Id, CookId, DateEntered, Active)
select
#Id, value as CookId, getDate(), 1
from
dbo.Split('123456,234567,345678', ',')
left join
dbo.Cook ck on ck.Id = #Id
where
not exists (select CookId from dbo.Cook where Id = #Id)
Then I tried a version with a table which winds up returning all the values in my #ids table including the cook number that would be a duplicate:
declare #ids table (id int)
insert into #ids
select value as id
from dbo.Split('123456,234567,345678', ',')
insert into dbo.Cook(Id, CookId, DateEntered, Active)
select
#Id, id as CookId, getDate(), 1
from
#ids
left outer join
dbo.Cook ck on ck.CookId = id
where
not exists (select CookId from dbo.Cook where ck.CookId != id)

I have the solution to my problem, thanks goes out to a fellow programmer. My problem was I should have being doing the join on the select statement and adding a comparison column to get the information I was looking for. The solution was this:
insert into dbo.Cook(Id, CookId, DateEntered, Active)
select
#Id, value as CookId, getDate(), 1
from
dbo.Split('123456,234567,345678', ',') c
left join
(select cook from dbo.Cook where Id = #Id) cook on cook.Id = c.value
where
cook.Id is null

Aside from your neglecting to put your from clause on a new line cringe, I believe it is your syntax.
I don't understand what you are trying to do here. dbo.Split is not a built in function in SQL Server as far as I know.

Related

IF ELSE condition with SQL Server trigger

I am populating a table entirely using triggers, it populates the table if LocationID and ProductID does not exists and if it already does it updates the given data.
I have posted the following code snippet looking for a possible solution or link to one.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[newpurchase]
ON [dbo].[PurchaseMaster]
AFTER INSERT
AS
BEGIN
IF (((SELECT COUNT(*) FROM StockMaster
WHERE LocationID = (SELECT LocationID FROM inserted)) > 0)
AND ((SELECT COUNT(*) FROM StockMaster
WHERE LocationID = (SELECT LocationID FROM inserted)) > 0))
UPDATE StockMaster
SET TotalPurchased = TotalPurchased + (SELECT PurchasedQTY FROM inserted)
WHERE LocationID = (SELECT LocationID FROM inserted)
AND ProductID = (SELECT ProductID FROM inserted);
ELSE
INSERT INTO StockMaster (LocationID, ProductID, TotalPurchased, TotalSold, OnHand)
SELECT LocationID, ProductID, PurchasedQTY, 0, 0 FROM inserted;
END
I am not entirely sure exactly what you are looking for. If your return sets cannot be collected dynamically, and you need another table to always update based off the information persisted by another another table then I do think triggers are fine. There is always overhead with triggers, so keep that in mind.
You could do the way you are doing it, and from what I can see on the surface level the trigger may be what you are looking for (but this also depends upon your business needs and relationships of tables). HOWEVER, you will have to be careful if your Insert is a bulk insert then what you have will throw an error.
I also noticed your If statement is checking LocationId twice instead of LocationId and ProductId.
The trigger you are trying to create works with only one value at a time. You could rewrite this to a more set based trigger for when bulk inserts occur. This way if you have one insert or bulk inserts these two queries can perform for that values where needed.
first you want to update all the values where LocationId and ProductId are the >same found in StockMaster
if no values match then nothing will be updated
Update StockMaster
Set TotalPurchased = sm.TotalPurchased + i.PurchasedQty
From StockMaster sm
inner join inserted i on sm.LocationId = i.LocationId and sm.ProductId = i.ProductId
next you want to insert any row that isn't found in StockMaster
if all values matched above, they will be weeded out with the wheree condition >and,then nothing would be inserted here, those that didn't match would be
inserted
INSERT INTO StockMaster (LocationID, ProductID, TotalPurchased, TotalSold, OnHand)
SELECT i.LocationID, i.ProductID, i.PurchasedQTY, 0, 0
FROM inserted i
left join StockMaster sm on i.LocationId = sm.LocationId and i.ProductId = sm.ProductId
where sm.{Id} is null;--not {id} is for whatever key this table uses

How to select from a master table but replace certain rows using a secondary, linked table?

I have two tables with a foreign key relationship on an ID. I'll refer to them as master and secondary to make things easier and also not worry about the FK for now. Here is cut down, easy to reproduce example using table variables to represent the problem:
DECLARE #Master TABLE (
[MasterID] Uniqueidentifier NOT NULL
,[Description] NVARCHAR(50)
)
DECLARE #Secondary TABLE (
[SecondaryID] Uniqueidentifier NOT NULL
,[MasterID] Uniqueidentifier NOT NULL
,[OtherInfo] NVARCHAR(50)
)
INSERT INTO #Master ([MasterID], [Description])
VALUES ('0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3', 'Test')
,('2696ECD2-FFDB-4E26-83D0-F146ED419C9C', 'Test 2')
,('F21568F0-59C5-4950-B936-AA73DA6009B5', 'Test 3')
INSERT INTO #Secondary (SecondaryID, MasterID, Otherinfo)
VALUES ('514673A6-8B5C-429B-905F-15BD8B55CB5D','0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3','Other info')
SELECT [MasterID], [Description], NULL AS [OtherInfo] FROM #Master
UNION
SELECT S.[MasterID], M.[Description], [OtherInfo] FROM #Secondary S
JOIN #Master M ON M.MasterID = S.MasterID
With the results.....
0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3 Test NULL
0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3 Test Other info
F21568F0-59C5-4950-B936-AA73DA6009B5 Test 3 NULL
2696ECD2-FFDB-4E26-83D0-F146ED419C9C Test 2 NULL
.... I would like to only return records from #Secondary if there is a duplicate MasterID, so this is my expected output:
0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3 Test Other info
F21568F0-59C5-4950-B936-AA73DA6009B5 Test 3 NULL
2696ECD2-FFDB-4E26-83D0-F146ED419C9C Test 2 NULL
I tried inserting my union query into a temporary table, then using a CTE with the partition function. This kind of works but unfortunately returns the row from the #Master table rather than the #Secondary table (regardless of the order I select). See below.
DECLARE #Results TABLE (MasterID UNIQUEIDENTIFIER,[Description] NVARCHAR(50),OtherInfo NVARCHAR(50))
INSERT INTO #Results
SELECT [MasterID], [Description], NULL AS [OtherInfo] FROM #Master
UNION
SELECT S.[MasterID], M.[Description], [OtherInfo] FROM #Secondary S
JOIN #Master M ON M.MasterID = S.MasterID
;WITH CTE AS (
SELECT *, RN= ROW_NUMBER() OVER (PARTITION BY [MasterID] ORDER BY [Description] DESC) FROM #Results
)
SELECT * FROM CTE WHERE RN =1
Results:
0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3 Test NULL 1
F21568F0-59C5-4950-B936-AA73DA6009B5 Test 3 NULL 1
2696ECD2-FFDB-4E26-83D0-F146ED419C9C Test 2 NULL 1
Note that I am not just trying to select the rows which have a value for OtherInfo, this is just to help differentiate the two tables in the result set.
Just to reiterate, what I need to only return the rows present in #Secondary, when there is a duplicate MasterID. If #Secondary has a row for a particular MasterID, I don't need the row from #Master. I hope this makes sense.
What is the best way to do this? I am happy to redesign my database structure. I'm effectively trying to have a master list of items but sometimes take one of those and assign extra info to it + tie it to another ID. In this instance, that record replaces the master list.
You are way overcomplicating this. All you need is a left join.
SELECT M.[MasterID], M.[Description], S.[OtherInfo] FROM #Master M
LEFT JOIN #Secondary S ON M.MasterID = S.MasterID
Union seems to be the wrong approach... I would suggest a left join:
SELECT m.[MasterID], m.[Description], s.[OtherInfo]
FROM #Master m
LEFT JOIN #Secondary s ON s.MasterID = m.MasterID

Compare tables base on Id and generate Insert statement

I have two DB(every thing is same schema, etc...) staging & Prod.
Both has table called "Prod.Product" & "Staging.Product"
I would like to compare these two tables base on id for example Id=1 and generate insert statement
select * from Prod.Product
except
select * from Staging.Product
Why do you need to generate insert statement? Just execute it. As far as I understand, you want to insert in Prod.Product the rows from Staging.Product with ID values that does not exists. You can do it like this:
insert into Prod.Product
select * from Staging.Product s
where not exists(select 1 from Prod.Product p where p.Id = s.Id)

Pre-Populate foreign keys in SQL with a new row

I am trying to write a SQL script which will go through a table with a newly created FK and pre-populate the key with a new row in the foreign table. I'm not 100% on how to do this or if its even possible in a single statement but here's my attempt:
UPDATE [dbo].[Blogs]
set AuthorSecurableId = inserted.Id
FROM [dbo].[Blogs] updating
INNER JOIN
(INSERT INTO [dbo].[Securables] (Name)
OUTPUT Inserted.id, ROW_NUMBER() OVER (ORDER BY Inserted.Id) as rownum
SELECT 'Admin : ' + Name
FROM Blogs
WHERE AuthorSecurableId is null) inserted ON ROW_NUMBER() OVER (ORDER BY updating.Id) = inserted.rownum
WHERE updating.AuthorSecurableId is null
When I do this I get the following error
Msg 10727, Level 15, State 1, Line 5
A nested INSERT, UPDATE, DELETE, or MERGE statement is not allowed on either side of a JOIN or APPLY operator.
Below is a simple view of the schema I have
I would like to create a securable for each blog which doesn't have one and populate that blogs AuthorSecurableId with the ID of the newly created securable
I think I could do this with a cursor but I was wondering if there is a better single statement approach
You can use merge against Securables with output to a table variable or temp table and a separate update against Blogs.
declare #T table
(
SecID int,
BlogID int
);
merge Securables T
using (
select 'Admin : '+B.Name as Name, B.Id
from Blogs as B
where B.AuthorSecurabledId is null
) as S
on 0 = 1
when not matched by target then
insert (Name) values (S.Name)
output inserted.Id, S.Id
into #T;
update Blogs
set AuthorSecurabledId = T.SecID
from #T as T
where Blogs.Id = t.BlogID;
SQL Fiddle

Joining Data Between 2 SQL Tables

Okay, I'm not as SQL savvy as I should be, but I'm familiar with how Joins, Unions, etc... work and I just can't come up with a solution for this. I'm trying to get data from two different tables, but the monkey wrench is that the right side table may have more rows than I actually want in my result set. The only criteria I have to join the two tables is an email address. Here's the code:
CREATE TABLE #PPEInfo(StudentEmail nvarchar(128), StudentName nvarchar(128), DevUnits int)
INSERT INTO #PPEInfo (StudentEmail, DevUnits)
SELECT e.StudentEmail AS Email, sum(ck.DevelopmentUnits) AS DevUnits
FROM Enrollments e, CourseKeys ck
WHERE e.CertGenerated = 'true'
AND e.CourseId = ck.CourseId
GROUP BY e.StudentEmail
ORDER BY DevUnits DESC
SELECT p.StudentEmail, p.DevUnits, s.StudentName
FROM #PPEInfo p
RIGHT OUTER JOIN Surveys s
ON p.StudentEmail = s.StudentEmail
ORDER BY DevUnits DESC, StudentName ASC
DROP TABLE #PPEInfo
The problem is that I receive multiple student names because they may not have used the same one when doing their submissions. For instance:
Email Address James R. Salvati
Email Address James Salvati
The only solution that I've come up with is to populate my temp table with the email addresses first and then query the Surveys table for the name using "TOP(1)" to get only one student name. It does work, but it's very CPU intensive, and I'm dealing with a lot of records. Here's the code (although I didn't care about the DevUnits at this point was just trying to come up with something):
CREATE TABLE #PPEInfo(ID int IDENTITY(1,1), StudentEmail nvarchar(128), StudentName nvarchar(128), DevUnits int)
INSERT INTO #PPEInfo (StudentEmail)
SELECT DISTINCT StudentEmail FROM Enrollments
WHERE CertGenerated = 'true'
DECLARE #rowID int
DECLARE #email nvarchar(128)
SET #rowID = (SELECT max(ID) FROM #PPEInfo)
WHILE (#rowID > 0)
BEGIN
SET #email = (SELECT StudentEmail FROM #PPEInfo WHERE ID = #rowID)
UPDATE #PPEInfo
SET StudentName = (SELECT TOP(1) s.StudentName FROM Surveys s
WHERE s.StudentEmail = #email)
WHERE ID = #rowID
SET #rowID = #rowID - 1
END
SELECT * FROM #PPEInfo
ORDER BY DevUnits DESC
DROP TABLE #PPEInfo
I've never had to actually post on one of these boards. I usually find the solution or figure one out, but this one is just beyond my SQL prowess.
Thanks!!!
It depends on how you want to determine which name to select when there are multiple. One posible way is below:
SELECT p.StudentEmail, p.DevUnits, MAX(s.StudentName)
FROM #PPEInfo p
RIGHT OUTER JOIN Surveys s
ON p.StudentEmail = s.StudentEmail
ORDER BY DevUnits DESC, StudentName ASC
GROUP BY p.studentEmail, p.devUnits
Here you are grouping by email and units and grabbing the "MAX" student name.
Also in your first query you should stop using implicit joins.
Correct me if I'm wrong, but I'm pretty sure that you can do this to achieve what you want:
select * from enrollments
inner join coursekeys on
enrollments.studentemail = coursekeys.studentemail
where coursekeys.studentname=(
select top 1 studentname from coursekeys
where studentemail=enrollments.studentemail
);
I don't have access to a SQL Server at the moment, but I've succesfully achieved this on a MySQL server with similar tables to yours.