Update table gives primary key violation error - sql-server

I have following tow tables
create table #temp(id int,rid int)
insert into #temp
select 1,1
union all
select 2,1
union all
select 3,1
select * from #temp
drop table #temp1
create table #temp1(id int, nid int,PRIMARY KEY CLUSTERED
(
id asc,nid asc
))
insert into #temp1
select 1,10
union all
select 2,10
union all
select 2,11
union all
select 3,10
Following are the both result sets:
id rid
1 1
2 1
3 1
id nid
1 10
2 10
2 11
3 10
I want to update #temp1 table with value from rid field of #temp table by matching id field from both tables. See following query:
select a.*
from #temp1 a inner join #temp b
on a.id = b.id
where a.id <> b.rid
It returns:
id nid
2 10
2 11
3 10
I want to update id with following query:
update a
set a.id = b.rid
-- select a.*
from #temp1 a inner join #temp b
on a.id = b.id
where a.id <> b.rid
But it returns
primary key violation error because of primary key in table #temp1.
I would like to delete the value if it is already exist if not then I would like to update
for example
id nid
1 10
2 10-- want to update but not able to this bcoz it violates primary key so delete this row.
2 11-- able to update this row but other 2 rows causing an issue.
3 10-- want to update but not able to this bcoz it violates primary key so delete this row.
Please suggest other ways to do this.

Because You are Violating the Primary Key Constraints
Check Below Tables
select B.*
from #temp1 a inner join #temp b
on a.id = b.id
where a.id <> b.rid
id rid
2 1
2 1
3 1
select * from #temp1
id nid
1 10
2 10
2 11
3 10
You are setting ID of above first table using join from #temp which already in #temp1
You Are attempt to Update Values which are already in #temp1 where id=2,2,3

select *
from #temp1 a inner join #temp b
on a.id = b.id
where a.id <> b.rid
You would be updating two id 2 records to the same value. You cannot do this, period. There is no other method to fix this except to drop the PK which I would suggest would be bad idea.
It is possible you need some further definition in your pdate to specify which of multiple records you want to update or you may need to delete the record which might end up as a duplicate before you do the update. Not knowing the business rules for what you are actually trying to accomplish or what your data means, it is impossiblet say what you can do to solve your problem. This ia case where the solution is dependant on the meaning and of course we have no meaning here.

Related

SQL Remove row where value exist and subsequent column that has the value

I am trying to write a SQL statement that first gets only the distinct values of column 1, I then want to compare this with the same table but remove any rows that have a value in column 2
For example, the value 10142 in FieldID when I write a select that doesn't include 10142 it only removes the 1 row but also the subsequent ID column to have no rows.
So in the screenshot, I should only see all results for only ID 634 as 633 has the FieldID value 10142.
I tried initially getting a distinct ID value into a temporary table and then filtering in another select where the FieldID was not equal to 10142 but still not seeing the correct result.
This is my query:
SELECT DISTINCT id
INTO #TEMP
FROM tbl_WorkItemCustomLatest
ORDER BY ID ASC
SELECT a.*
FROM #TEMP
INNER JOIN dbo.tbl_WorkItemCustomLatest AS A ON #TEMP.id = A.id
WHERE A.FieldID != 10142
ORDER BY A.ID ASC
Any help is much appreciated.
With NOT EXISTS:
select t.* from tbl_WorkItemCustomLatest t
where not exists (
select 1 from tbl_WorkItemCustomLatest
where id = t.id and FieldId = 10142
)
or with NOT IN:
select * from tbl_WorkItemCustomLatest
where id not in (select id from tbl_WorkItemCustomLatest where FieldId = 10142)

Discard specific results on stored procedure SQL Server

Let's say that i have a stored procedure which returns all data from two tables: A and B.
Table_A
Id Name
-----------------
1 Chuck
2 Richard
3 Arthur
Table_B
Status Nickname IdTableA
-----------------------------
1 cthulhu 1
2 Poe 3
And the query:
SELECT
a.Name, b.Status, b.Nickname
FROM
Table_A a
LEFT JOIN
Table_B b ON b.IdTableA = a.Id
If I run the stored procedure right now, it returns all the records, even when they don't have a record in table_B (as you can see, record number 2 from table_A does not exist yet -maybe tomorrow, or in a month...-). What I need to do is discard the status number 2 (which lives on table B). The problem happens when I use something like:
where b.Status = 1
or
where b.Status <> 2
Why? Because it returns only the values with Status 1. I need only discard records with status 2, but return also the records from table_A without records on table_B.
There's a way to do that?
Hope you can help me. Thanks in advance.
Does the following screenshot fulfil your requirement?
try the following:
declare #table_a table (id int, name varchar(100))
insert into #table_a select 1, 'Chuck'
union select 2, 'Richard'
union select 3, 'Arthur'
declare #table_b table (status int, nickname varchar(100), id_table_a int)
insert into #table_b
select 1, 'cthulhu', 1
union select 2, 'Poe', 3
select * from #table_a
select * from #table_b
select *
from #table_a a
left join #table_b b on a.id = b.id_table_a
where isnull(status,'') <> 2

SQL Server - Can someone explain this Query?

I have a query that I can't understand. Can someone explain to me what is going on with all these commas ?
SELECT * FROM TABLE1
LEFT OUTER JOIN TABLE2 ON TABLE1.Column1 = TABLE2.Column1,
TABLE3, TABLE4, TABLE5, TABLE6
WHERE [...]
I don't get the part where a bunch or tables are listed. I figured out by the WHERE part that it was bound or at least used like in a "FROM" use. Can someone explain to me what is it and the name or at least have a link to the documentation of this form of link ?
Thanks a lot.
This means you Are Joining TABLE1 and TABLE2 using LEFT JOIN
So If there is a Matching value in TABLE2.Column1 for TABLE1.Column1 that Value will be displayed and if there is no Match, then the Column Will be there but Value will be NULL
For all other Tables, you are using a CROSS JOIN. So It will create a Cartesian Product with the Records obtained from the First Join
DECLARE #TABLEA TABLE
(
ColA INT
)
DECLARE #TABLEB TABLE
(
ColB INT
)
DECLARE #TABLEC TABLE
(
ColC INT
)
DECLARE #TABLED TABLE
(
ColD INT
)
INSERT INTO #TABLEA
VALUES(1),(2),(3)
INSERT INTO #TABLEB
VALUES(4),(5),(6)
INSERT INTO #TABLEC
VALUES(7),(8),(9)
INSERT INTO #TABLED
VALUES(10)
SELECT
*
FROM #TABLEA A
LEFT JOIN #TABLEB B
ON A.ColA = B.ColB
,#TABLEC,#TABLED
In the above Example, TableA and TableB are LEFT JOINed and then TABLEC AND TABLED are Cross Joined with the Result. So my Final Output will be
ColA ColB ColC ColD
----------- ----------- ----------- -----------
1 NULL 7 10
1 NULL 8 10
1 NULL 9 10
2 NULL 7 10
2 NULL 8 10
2 NULL 9 10
3 NULL 7 10
3 NULL 8 10
3 NULL 9 10
You Can Filter the Records from any of the tables using the WHERE Clause

Is there a way to duplicate part of a adjacent list hierarchy given a starting id?

I have an adjacent list hierarchy model that makes up a topic structure
ID Parent_Id Topic_Name
1 Null Topic 1
2 Null Topic 2
3 2 Topic 3
4 3 Topic 4
5 2 Topic 5
6 Null Topic 6
This forms part of an application which I cant change - the topics dont have multiple parents so unfortunatly I can't move to a nested sets - although if this was an interim step in the process - this would be fine as long as it went back to adjacent list hierarchy model
I want to specify a topic id and then copy it to a new topic id and retain the levels / structure underneath
So in my example I could specify topic topic_id 2 and it would create
ID Parent_Id Topic_Name
7 Null Topic 2
8 7 Topic 3
9 8 Topic 4
10 7 Topic 5
Auto numbering is taken care of for the ID so no need to construct that, but obviously the parent id needs to be retained
How can I achieve the above? would I need to flatten the data and do 3 seperate inserts logging the id after each insert?
You can use a recursive CTE to get the rows to insert.
If you use merge to add the rows you can use output to capture a mapping between the generated ID and the old ID which can be used to update the column Parent_ID for the inserted rows.
-- ID for topic to copy
declare #ID int;
set #ID = 2;
-- Table to hold the inserted rows
declare #T table
(
New_ID int,
Old_ID int,
Old_ParentID int
);
-- Add rows from recursive CTE using merge
with C as
(
select T.ID, T.Parent_Id, T.Topic_Name
from YourTable as T
where T.ID = #ID
union all
select T.ID, T.Parent_Id, T.Topic_Name
from YourTable as T
inner join C
on C.ID = T.Parent_Id
)
merge YourTable
using C
on 0 = 1
when not matched then
insert (Topic_Name) values (C.Topic_Name)
output inserted.ID,
C.ID,
C.Parent_Id
into #T(New_ID, Old_ID, Old_ParentID);
-- Update Parent_Id for the new rows
update Y set
Parent_Id = T2.New_ID
from #T as T1
inner join #T as T2
on T1.Old_ParentID = T2.Old_ID
inner join YourTable as Y
on T1.New_ID = Y.ID;
SE-Data
Working example. Works in theory but probably not robust for high transaction volumes or fast enough for big tables.
--- sample table
create table tbl (
id int identity primary key,
parent_id int references tbl(id),
topic_name varchar(100));
insert tbl values
( Null, 'Topic 1'),
( 1, ' Topic 2'),
( 2 , ' Topic 3'),
( 3 , ' Topic 4'),
( 2 , ' Topic 5'),
( Null, ' Topic 6'),
( 4, ' Topic 4-3'),
( 7, ' Topic 5-4')
;
--- script to duplicate a hierarchy branch
declare #inserttbl table (
id int,
parent_id int,
topic_name varchar(100));
;with cte as (
select id, parent_id, topic_name
from tbl
where id=2 -- or parameter
union all
select t.id, t.parent_id, t.topic_name
from tbl t
join cte c on t.parent_id=c.id
), cte2 as (
select *,rn=row_number() over (order by id)
from cte
), cte3 as (
select rec.*, par.rn as parent_rn
from cte2 rec
left join cte2 par on par.id=rec.parent_id
)
insert #inserttbl
select cte3.rn,
case when cte3.rn=1 then cte3.parent_id
else cte3.parent_rn end,
topic_name
from cte3;
insert tbl(topic_name)
select topic_name from #inserttbl order by id;
declare #delta int=scope_identity()-##rowcount;
update t
set parent_id = i.parent_id + case when i.id=1 then 0
else #delta end
from tbl t
join #inserttbl i on t.id - #delta = i.id;
--- check results
select * from tbl;

Return NULL columns if IDs don't exist in the table

I have one solution with left join for the below question, but I'm looking for more efficient query
Select * from table1 where Id in (1,2,3,4,5);
returns all the existing "Ids" in the table. Now I want all the Ids to be returned with null columns if the Id is not existing in the table.
EX: Result must contain 3 and 5 though the IDs not existing in the table
ID Name Designation
1 John Employee
2 Nar Manager
3 **NULL** **NULL**
4 Esh Executive.
5 **NULL** **NULL**
select x.id, y.name, y.designation
from (
select row_number() OVER(order by id) as id
from table1
) x
left join table1 y
on x.id = y.id
This ought to work.

Resources