Insert where not exists Violation of PRIMARY KEY - sql

I'm having troubles with an Insert where not exists and I'm not sure if a MERGE statement would be more efficient or what's wrong with my statement.
I have en existing View and need to insert the new records of this View into a Table.
The Table looks like:
CREATE TABLE [dbo].[ser_number_all]
(Serialnumber nvarchar(100) PRIMARY KEY,
TypeName nvarchar(max),
Date datetime,
Parent_Serialnumber nvarchar(100),
JobNumber nvarchar(30),
ProductNode hierarchyid,
);
The Insert statement looks like this:
insert into [dbo].[ser_number_all]
( Serialnumber
, TypeName
, Date
, Parent_Serialnumber
, JobNumber
, ProductNode)
select Serialnumber
, TypeName
, Date
, Parent_Serialnumber
, JobNumber
, ProductNode
from dbo.Hierachical_View_with_Jobnumbers as ser_number_all
where not exists (select 1
from Hierachical_View_with_Jobnumbers as hv
where hv. Serialnumber = ser_number_all.Serialnumber
and hv. TypeName = ser_number_all.TypeName
and hv. Date = ser_number_all.Date
and hv. Parent_Serialnumber = ser_number_all.Parent_Serialnumber
and hv. JobNumber = ser_number_all.JobNumber
and hv. ProductNode = ser_number_all.ProductNode);
As long the View has not any new records, it looks ok and I'm not getting any error, the output is 0 records as it should be.
When I add a new record to the origin table and the view has 1 record more, I'm always getting this error:
Msg 2627, Level 14, State 1, Line 4
Violation of PRIMARY KEY constraint 'PK__ser_numb__F2753A12C4ABA976'. Cannot insert duplicate key in object 'dbo.ser_number_all'. The duplicate key value is (.x3666AB05).
The statement has been terminated.
I don't get it why it will insert a duplicate value in the primary key column because in my WHERE clause I can't see any mistake.
I have also tried with IS NULL instead = ser_number_all.TypeName and for all other columns where it could have a NULL value, but still the same.
Again, I'm coming from Oracle and it looks like I have to learn many diversities with MS SQL compared to Oracle.
Appreciate any suggestion :-)
Thx
EDIT:
Here the code of the View:
CREATE VIEW [dbo].[Hierachical_View_with_Jobnumbers]
AS
WITH ProductList
AS
(
SELECT p.Serialnumber,
p.Type_Id,
p.Parent_Serialnumber,
p.ActiveJob_Jobnumber as JobNumber,
N'/' + CONVERT(NVARCHAR(4000), ROW_NUMBER() OVER (ORDER BY p.Serialnumber)) + N'/' AS ProductNode_AsChar
FROM Products AS p
WHERE p.Parent_Serialnumber IS NULL
UNION ALL
SELECT p.Serialnumber,
p.Type_Id,
p.Parent_Serialnumber,
JobNumber,
pl.ProductNode_AsChar + CONVERT(NVARCHAR(4000), ROW_NUMBER() OVER (ORDER BY p.Serialnumber)) + N'/'
FROM Products AS p
INNER JOIN ProductList AS pl ON p.Parent_Serialnumber = pl.Serialnumber
)
SELECT Serialnumber,
pt.Name as TypeName,
Parent_Serialnumber,
JobNumber,
CONVERT(HIERARCHYID, ProductNode_AsChar) AS ProductNode
FROM ProductList as pl
INNER JOIN ProductTypes as pt on pl.Type_Id = pt.Id;

#TheGameiswar
Sorry, now I got it what you meant ;-) Stupid me...
Here the solution which works now with correctly correlating:
insert into [dbo].[ser_number_all]
( Serialnumber
, TypeName
, Date
, Parent_Serialnumber
, JobNumber
, ProductNode)
select Serialnumber
, TypeName
, Date
, Parent_Serialnumber
, JobNumber
, ProductNode
from dbo.Hierachical_View_with_Jobnumbers as hv
where not exists (select 1
from ser_number_all as sna
where hv. Serialnumber = sna.Serialnumber);
Thank you all for your time and guiding me to the right direction :-)

Related

An aggregate may not appear in the set list of an UPDATE statement T-SQL

In T-SQL I'm attempting to update a stock user field with the number of weeks we expect it to be delivered to us by taking the difference between today and the purchase order due in dates. However the select query can return more than one line of purchase orders if there is more than one purchase order containing that product (obviously). I would like to take the smallest number it returns / minimum value but obviously cannot do this within the update query. Can anyone recommend a workaround? Thanks.
UPDATE [Exchequer].[ASAP01].[STOCK]
SET stUserField7 = DATEDIFF(day,CONVERT(VARCHAR(8), GETDATE(), 112),min(tlLineDate)) / 7 + 1
FROM [Exchequer].[ASAP01].[STOCK]
JOIN [Exchequer].[ASAP01].[CUSTSUPP]
ON stSupplier = acCode
JOIN [Exchequer].[ASAP01].[DETAILS]
ON stCode = tlStockCodeTrans1
WHERE stSupplier <> '' AND stQtyOnOrder > '0' AND stQtyOnOrder > stQtyAllocated
AND tlOurRef like 'POR%' AND (floor(tlQtyDel) + floor(tlQtyWOFF)) < floor(tlQty)
AND tlLineDate >= CONVERT(VARCHAR(8),GETDATE(), 112)
Why are you casting date to varchar for the difference?
This is not date but how you can use a window function in an update
declare #maps table(name varchar(10), isUsed bit, code varchar(10));
insert into #Maps values
('NY', 1, 'NY1')
, ('NY', 0, 'NY2')
, ('FL', 0, 'FL1')
, ('TX', 0, 'TX1')
declare #Results table (id int identity primary key, Name varchar(20), Value int, Code varchar(20), cnt int)
insert into #results values
('FL', 12, 'FL1', null)
, ('TX', 54, 'TX1', null)
, ('TX', 56, 'TX1', null)
, ('CA', 50, 'CA1', null)
, ('NJ', 40, 'NJ1', null)
select * from #results
order by name, Value desc
update r
set r.cnt = tt.cnt
from #results r
join ( select id, max(value) over (partition by name) as cnt
from #Results
) tt
on r.id = tt.id
select * from #results
order by name, value desc
Build a SELECT query with columns for the following:
The primary key of the [Exchequer].[ASAP01].[STOCK] table
The new desired stUserField7
Given the MIN(tlLineDate) expression in the original question, if this SELECT query does not have either a GROUP BY clause or change to use an APPLY instead of a JOIN, you've probably done something wrong.
Once you have that query, use it in an UPDATE statement like this:
UPDATE s
SET s.stUserField7 = t.NewValueFromSelectQuery
FROM [Exchequer].[ASAP01].[STOCK] s
INNER JOIN (
--- your new SELECT query here
) t ON t.<primary key field(s)> = s.<primary key field(s)>

Update table row with inserted identity ID

I have the following query:
INSERT INTO dbo.Products
( Code ,
ProducerCode ,
CustomerId ,
EanCode ,
ChangedDateTime ,
ChangedById ,
Deleted
)
SELECT Code ,
ProducerCode ,
CustomerId ,
EanCode ,
GETDATE(),
GETDATE(),
0
FROM dbo.BulkProducts
WHERE ProductId is NULL AND BulkProducts.BulkId = #BulkId
The Products table has an IDENTITY ID column, which is assigned automatically on insert. What I want to achieve is, after the insertion in Products, have the assigned ID of the product in the row from BulkProducts. I have read a bit about##IDENTITY, IDENT_CURRENT and SCOPE_IDENTITY but I cannot seem to get it to work for my example. Any help appreciated. I am using SQL Server 2012.
You can achieve it using Output clause, like this -
DECLARE #OutProduct TABLE
(
ProductID INT,
Code INT
)
INSERT INTO dbo.Products
( Code ,
ProducerCode ,
CustomerId ,
EanCode ,
ChangedDateTime ,
ChangedById ,
Deleted
)
OUTPUT INSERTED.ID, INSERTED.Code INTO #OutProduct (ProductID, Code)
SELECT Code ,
ProducerCode ,
CustomerId ,
EanCode ,
GETDATE(),
GETDATE(),
0
FROM dbo.BulkProducts
WHERE ProductId is NULL AND BulkProducts.BulkId = #BulkId
So Now all your inserted data are in #OutProduct table. Now you can update your BulkProducts table using that temp table like below.
UPDATE bprod
SET productID = tmp.ProductID
FROM BulkProducts bprod
INNER JOIN #OutProduct tmp
ON bprod.Code = tmp.Code
WHERE bprod.ProductId is NULL AND bprod.BulkId = #BulkId
Apparently this cannot be solved without a MERGE. The final solution looks like this:
MERGE INTO dbo.Products
USING dbo.BulkProducts AS src
ON 1 = 0 -- Never match
WHEN NOT MATCHED THEN
INSERT(EanCode, ChangedDateTime, ChangedById, Deleted)
VALUES(src.EanCode, GETDATE(), GETDATE(), 0)
OUTPUT
inserted.Id,
src.Id
INTO #OutProduct;
And like this, my #OutProduct table contains tuples of BulkProductId and ProductId which I can then use to update my BulkProducts table.

Query Slow down due to structure of WHERE clause

I have a query that creates an #TABLE of a population of interest. It's structure is like this:
DECLARE #SepsisTbl TABLE (
PK INT IDENTITY(1, 1) PRIMARY KEY
, Name VARCHAR(500)
, MRN INT
, Account INT
, Age INT -- Age at arrival
, Arrival DATETIME
, Triage_StartDT DATETIME
, Left_ED_DT DATETIME
, Disposition VARCHAR(500)
, Mortality CHAR(1)
);
WITH Patients AS (
SELECT UPPER(Patient) AS [Name]
, MR#
, Account
, DATEDIFF(YEAR, AgeDob, Arrival) AS [Age_at_Arrival]
, Arrival
, Triage_Start
, TimeLeftED
, Disposition
, CASE
WHEN Disposition IN (
'Medical Examiner', 'Morgue'
)
THEN 'Y'
ELSE 'N'
END AS [Mortality]
FROM SMSDSS.c_Wellsoft_Rpt_tbl
WHERE Triage_Start IS NOT NULL
AND (
Diagnosis LIKE '%SEPSIS%'
OR
Diagnosis LIKE '%SEPTIC%'
)
)
INSERT INTO #SepsisTbl
SELECT * FROM Patients
From this point forward I have 5 more queries of the same sort that are looking for different types of orders that I then LEFT OUTER JOIN onto this table. My question is, why does my performance degrade so much when I change the where clause of the tables from this:
AND A.Account IN (
SELECT Account
FROM SMSDSS.c_Wellsoft_Rpt_tbl
WHERE (
Diagnosis LIKE '%SEPSIS%'
OR
Diagnosis LIKE '%SEPTIC%'
)
to this:
AND A.Account IN (
SELECT Account
FROM #SepsisTbl
)
The run time goes from 2.5 minutes to over 10 minutes with still no results. The CTE itself runs as fast as I can press F5.
Thank you,
I suspect that the problem is because the table variable doesn't have an index on Account. If you add an index on Account then I would expect better performance.
See the answer to this question for details on how to add an index: Creating an index on a table variable

Get string by integer

I have a column in db stores Entityid and other one stores Entityname , i need a stored procedure that get name when user insert id (by column name), i have one am working on, how can i improve it.plz explain..
ALTER procedure [dbo].[Emp_CompanyHirarchy]
#FK_CompanyId varchar(50),
#FK_EntityId varchar(50)
AS
SELECT * FROM dbo.RetrieveEntityParent
WHERE (EntityId =#FK_EntityId)
when i excute this, error keeps raise:Msg 216, Level 16, State 1, Procedure Emp_CompanyHirarchy, Line 5
Parameters were not supplied for the function 'dbo.RetrieveEntityParent'.
the function dbo.RetrieveEntityParent:
ALTER FUNCTION [dbo].[RetrieveEntityParent] (#FK_EntityId int)
RETURNS TABLE
AS RETURN
with p as
(SELECT EntityId, FK_ParentId , EntityName ,EntityArabicName
FROM OrgEntity
WHERE OrgEntity.EntityId=#FK_EntityId
UNION ALL
SELECT PA.EntityId, PA.FK_ParentId, PA.EntityName,PA.EntityArabicName
FROM OrgEntity as PA
inner join p
ON p.FK_ParentId = PA.EntityId)
select * from p
There is an example for your need in this link , but there is a simpler way using the parameter directly in this link .
DECLARE #FK_EntityId INT
SET #FK_EntityId = 1
SELECT EntityId, FK_ParentId , EntityName ,EntityArabicName
FROM OrgEntity
WHERE OrgEntity.EntityId = #FK_EntityId
UNION ALL
SELECT EntityId, FK_ParentId , EntityName ,EntityArabicName
FROM OrgEntity
WHERE FK_ParentId = #FK_EntityId
I can't find Employee referred by Employee.FK_EntityId in your RetrieveEntityParent.
Do you mean OrgEntity.FK_EntityId
after your Edit, to get Emp_CompanyHirarchy work you would have to transfer #FK_EntityId as parameter
ALTER procedure [dbo].[Emp_CompanyHirarchy]
#FK_CompanyId varchar(50),
#FK_EntityId varchar(50)
AS
SELECT * FROM dbo.RetrieveEntityParent(#FK_EntityId)
-- WHERE mybe some other condition
BTW: there is some parametertype missmatch with varchar and integer

sql query serial number

I have written a stored procedure in SQL Server 2000. I want a serial number for output table.
So when I run this stored proc I get this error:
An explicit value for the identity column in table
'#tmpSearchResults1' can only be specified when a column list is used
and IDENTITY_INSERT is ON.
I have tried with set IDENTITY_INSERT #tmpSearchResults1 on
Create Procedure dbo.usp_mobile_All_KeyWord(#searchkey varchar(30))
AS
CREATE TABLE #tmpSearchResults
(
property_id varchar(255),
property_number varchar(255),
auction_date_reason varchar(255)
)
INSERT INTO #tmpSearchResults
SELECT
p.property_id, p.property_number, p.auction_date_reason
FROM
Pr p
INNER JOIN
Au a ON p.auction_id = a.auction_id
INNER JOIN
PrAdd pa ON p.property_id = pa.property_id
INNER JOIN state AS s ON s.state_id=pa.state
where
(
(p.archive = 'N'
AND
a.show_on_site = 'Y'
AND
(
(
((p.auction_date >= CONVERT(datetime, CONVERT(varchar, GETDATE(), 103), 103) and (p.auction_date_reason is null or p.auction_date_reason = ''))
or
(p.auction_date <= CONVERT(datetime, CONVERT(varchar, GETDATE(), 103), 103) and ( p.auction_date_reason = 'Accepting Offers' )))
and
pa.property_address_type_id = 1 )) )
and
(state_abbreviation=#searchkey or s.state_name like '%'+''+ #searchkey +''+'%' or city like '%'+''+ #searchkey +''+'%' or pa.address1 like '%'+''+ #searchkey +''+'%'
or pa.address2 like '%'+''+ #searchkey +''+'%')
)
)
CREATE TABLE #tmpSearchResults1
(
i1 int identity,
property_id varchar(255),
property_number varchar(255),
auction_date_reason varchar(255)
)
insert into #tmpSearchResults1
select
property_id ,
property_number,
auction_date_reason
from #tmpSearchResults
order by
case when charindex(#searchkey,state) >0 then 1000 else 0 end desc,
case when charindex(#searchkey,statename) >0 then 1000 else 0 end desc,
case when charindex(#searchkey,city) >0 then 1000 else 0 end desc,
case when charindex(#searchkey,address2) >0 then 1000 else 0 end desc,
case when charindex(#searchkey,address1) >0 then 1000 else 0 end desc,
case when charindex(#searchkey,short_description) >0 then 1000 else 0 end desc
select * from #tmpSearchResults1
Plz do help me
The error code is very very very clear.
The relevant portion is ...when a column list is used....
You need to specify your column list in the INSERT statement.
INSERT INTO #tmpSearchResults
(i1,
property_id,
property_number,
auction_date_reason)
SELECT
p.property_id, p.property_number, p.auction_date_reason
FROM...
First, there is a comma too much in the SELECT part of your second statement:
insert into #tmpSearchResults1
select
property_id ,
property_number,
auction_date_reason , <-- THIS ONE!!
from #tmpSearchResults
The last column of a SELECT statement must be without a comma.
So this would be correct:
insert into #tmpSearchResults1
select
property_id ,
property_number,
auction_date_reason
from #tmpSearchResults
Second, did you read this part of the error message?
An explicit value [...] can only be specified when a column list is used
The "column list" part means that you have to specify the columns in the INSERT part:
insert into #tmpSearchResults1
(property_id, property_number, auction_date_reason)
select
property_id ,
property_number,
auction_date_reason
from #tmpSearchResults
You can get away with not specifying the columns when the number of columns in the SELECT statement is the same as in the table in which they should be inserted (and if the data types match).
If one of these conditions is not met, you need to specify the columns because otherwise SQL Server doesn't know which value to insert into which column.