Violation on primary key with multiple keys in table - sql

CREATE TABLE parameters (
tag_id BIGINT,
id NVARCHAR(255),
idx NVARCHAR(255),
primary key (tag_id, idx)
);
CREATE TABLE tag
([oid] int, [Name] varchar(1))
;
INSERT INTO tag
([oid], [Name])
VALUES
(1, 'A'),
(2, 'B'),
(3, 'C'),
(4, 'D')
;
INSERT parameters (tag_id, id, idx)
SELECT tag.oid, id.a, idx.a
FROM
( VALUES (1), (0), ('A'), (2) ) AS id(a),
( VALUES ('a'), ('b'), ('c'), ('d') ) AS idx(a),
tag
This should be output:
tag_id id idx
______________________________________________
1 1 a
1 0 b
1 A c
1 2 d
2 1 a
2 0 b
2 A c
2 2 d
3 1 a
3 0 b
3 A c
3 2 d
4 1 a
4 0 b
4 A c
4 2 d
Below is the error which I am getting:
Cannot insert duplicate key in object 'tag_parameters'. The duplicate
key value is (1, a).
Why if I have only one combination (1, a). The next one is (2, a).

You can use same column idx in single values construct :
SELECT t.oid, a.id, a.idx
FROM tag t CROSS JOIN
( VALUES ('1', 'a'), ('0', 'b'), ('A', 'c'), ('2', 'd')
) AS a(id, idx);

Related

Remove duplicate value in different categories in same table SQL but keep the first category value

Let's say I have a table with id and category like the table below
D_id | D_category
-----------------
1 | A
2 | A
3 | A
1 | B
2 | B
4 | B
5 | B
1 | C
2 | C
4 | C
5 | C
6 | C
Hence the rules are like this
values in category A should not be appear in category B and category C
values in category B should not be appear in category C
The end result should be like this
D_id | D_category
-----------------
1 | A
2 | A
3 | A
4 | B
5 | B
6 | C
I will provide a solution that works but its not an ideal solution can anyone help me to provide a better solution in case there are more categories meaning that if there are more category then it should follow the rules the values in previous categories should not appear in any other categories
DECLARE #A TABLE(
D_id INT NOT NULL,
D_category VARCHAR(MAX));
INSERT INTO #A(D_id,D_category)
VALUES (1, 'A'),
(2, 'A'),
(3, 'A'),
(1, 'B'),
(2, 'B'),
(4, 'B'),
(5, 'B'),
(1, 'C'),
(2, 'C'),
(4, 'C'),
(5, 'C'),
(6, 'C')
DELETE t
FROM #A t
WHERE t.D_category = 'B' AND EXISTS (SELECT 1 FROM #A t2 WHERE t2.D_category = 'A' and t.D_id = t2.D_id)
DELETE t
FROM #A t
WHERE t.D_category = 'C' AND EXISTS (SELECT 1 FROM #A t2 WHERE t2.D_category = 'B' and t.D_id = t2.D_id)
DELETE t
FROM #A t
WHERE t.D_category = 'C' AND EXISTS (SELECT 1 FROM #A t2 WHERE t2.D_category = 'A' and t.D_id = t2.D_id)
select * from #A
Just check that the specified record doesn't exist earlier in the sequence.
select *
from #A A1
where not exists (
select 1
from #A A2
where A2.D_id = A1.D_id
and A2.D_category < A1.D_category
)
or just make use of row_number()
select *
from
(
select *, r = row_number() over (partition by D_id order by D_category)
from #A
) a
where a.r = 1
Delete using the join syntax:
delete a
from my_table a
join my_table b on a.D_id = b.D_id
and a.D_category > b.D_category
See live demo.

Sql Server - FULL JOIN splitting up the result rather than returning a joined dataset

Suppose I have the following (very simplified) schema / data set up in SQL Server:
CREATE TABLE #Ids1 (Id1 VARCHAR(1));
CREATE TABLE #Vals1 (Id1 VARCHAR(1), Id2 VARCHAR(1));
CREATE TABLE #Ids2 (Id1 VARCHAR(1));
CREATE TABLE #Vals2 (Id1 VARCHAR(1), Id2 VARCHAR(1));
INSERT INTO #Ids1 (Id1) VALUES ('a'), ('b'), ('c'), ('d');
INSERT INTO #Vals1 (Id1, Id2) VALUES ('a', '1'), ('b', '2'), ('c', '3'), ('d', '4');
INSERT INTO #Ids2 (Id1) VALUES ('a'), ('b'), ('c'), ('e'), ('f'), ('g');
INSERT INTO #Vals2 (Id1, Id2) VALUES ('a', '1'), ('b', '2'), ('c', '3'), ('e', '5'), ('f', '6'), ('g', '7');
Basically, I have 2 similar datasets - One ending with a 1 suffix, the other ending with a 2 suffix and there is a chance either of the datasets may have data that is not in the other set.
What I would like to do is create a query that returns a single joined dataset that would look as follows:
#Ids1.Id1 #vals1.Id1 #vals1.Id2 #Ids2.Id1 #Vals2.Id1 #Vals2.Id2
a a 1 a a 1
b b 2 b b 2
c c 3 c c 3
d d 4 NULL NULL NULL
NULL NULL NULL e e 5
NULL NULL NULL f f 6
NULL NULL NULL g g 7
I figured the following SQL would accomplish this:
SELECT
*
FROM
#Ids1
FULL JOIN #Vals1
ON #Vals1.Id1 = #Ids1.Id1
FULL JOIN #Ids2
ON #Ids2.Id1 = #Ids1.Id1
FULL JOIN #Vals2
ON #Vals2.Id1 = #Ids2.Id1
AND #Vals2.Id2 = #Vals1.Id2
but it is separating out the last tables rather than joining them, so it ends up looking as follows:
#Ids1.Id1 #vals1.Id1 #vals1.Id2 #Ids2.Id1 #Vals2.Id1 #Vals2.Id2
a a 1 a a 1
b b 2 b b 2
c c 3 c c 3
d d 4 NULL NULL NULL
NULL NULL NULL e NULL NULL
NULL NULL NULL f NULL NULL
NULL NULL NULL g NULL NULL
NULL NULL NULL NULL e 5
NULL NULL NULL NULL f 6
NULL NULL NULL NULL g 7
I've created a link to the prepared Schema and the SQL at the following URL:
http://rextester.com/SAX53638
I'm guessing / hoping I'm just missing something simple, but I just can't seem to get it to work. What's the best way to return the data I want?
Join the tables internally and then join again
Try using the below the query
SELECT
*
FROM
(SELECT
Ids1.Id1 AS Id11,
vals1.Id1 AS Idv11,
vals1.Id2 AS Idv12
FROM
Ids1
FULL JOIN Vals1
ON Vals1.Id1 = Ids1.Id1) Ivs1
FULL JOIN
(SELECT
Ids2.Id1 AS Id21,
vals2.Id1 AS Idv21,
vals2.Id2 AS Idv22
FROM
Ids2
FULL JOIN Vals2
ON Vals2.Id1 = Ids2.Id1) Ivs2
ON Ivs1.Id11 = Ivs2.Id21;

how to do partitioning on VARCHAR column

DECLARE #Table1 TABLE
(ID int, STATUS varchar(1))
;
INSERT INTO #Table1
(ID, STATUS)
VALUES
(1, 'A'),
(1, 'A'),
(1, 'A'),
(1, 'B'),
(1, 'A'),
(2, 'C'),
(2, 'C')
;
Script :
Select *,ROW_NUMBER()OVER(PARTITION BY STATUS ORDER BY (SELECT NULL))RN from #Table1
Getting Result Set
ID STATUS RN
1 A 1
1 A 2
1 A 3
1 A 4
1 B 1
2 C 1
2 C 2
Need Output
ID STATUS RN
1 A 1
1 A 2
1 A 3
1 B 1
1 A 1
2 C 1
2 C 2
Try this
DECLARE #Table1 TABLE
(ID int, STATUS varchar(1));
INSERT INTO #Table1
(ID, STATUS)
VALUES
(1, 'A'),
(1, 'A'),
(1, 'A'),
(1, 'B'),
(1, 'A'),
(2, 'C'),
(2, 'C');
;WITH Tmp
AS
(
SELECT *, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNumber FROM #Table1
)
SELECT
A.ID ,
A.STATUS ,
ROW_NUMBER() OVER (PARTITION BY A.STATUS, (A.RowNumber - A.RN) ORDER BY (SELECT NULL)) AS RN
FROM
(
Select *, ROW_NUMBER() OVER(PARTITION BY STATUS ORDER BY RowNumber) AS RN from tmp
) A
ORDER BY
A.RowNumber
Output:
ID STATUS RN
----------- ------ ------
1 A 1
1 A 2
1 A 3
1 B 1
1 A 1
2 C 1
2 C 2
Firstly, In the insert statement that you posted. How is 4 different from 1,2 and 3, if it is based on a different column then include that column as well in "row_number" in partition by sub clause. Because otherwise it will think that 'A' in 4 and 'A' in 1,2,3 are same and therefore group them together.
INSERT INTO #Table1
(ID, STATUS)
VALUES
(1, 'A'), <-- 1
(1, 'A'), <-- 2
(1, 'A'), <-- 3
(1, 'B'),
(1, 'A'), <-- 4
(2, 'C'),
(2, 'C')
;

Delete duplicate in sql based on other column value

I want to remove duplicates based on below condition.
My table contains data like cross relation. Column 1 value exist in column 2 and vice versa.
sample table
id id1
-------------
1 2
2 1
3 4
4 3
5 6
6 5
7 8
8 7
I want to delete 1 row from first two rows, same from third and forth, same for fifth and sixth and so on..
Can anyone please help?
Like this way you are going to delete just the second row from each group of 2 rows:
CREATE TABLE [LIST_ID](
[ID] [NUMERIC](4, 0) NOT NULL,
[ID_1] [NUMERIC](4, 0) NOT NULL
);
INSERT INTO LIST_ID (ID, ID_1)
VALUES
(1, 2),
(2, 1),
(3, 4),
(4, 3),
(5, 6),
(6, 5);
WITH First_Row AS
(
SELECT ROW_NUMBER() OVER (ORDER BY ID ASC) AS Row_Number, *
FROM LIST_ID
)
DELETE FROM First_Row WHERE Row_Number % 2 ='0';
SELECT * FROM LIST_ID;
How about this:
DELETE
FROM myTable
WHERE id IN (
SELECT CASE WHEN id < id1 THEN id ELSE id1 END
FROM myTable
)
Where myTable is the sample table with data.
declare #t table (id1 int, id2 int)
insert into #t (id1, id2)
values
(1, 2),
(2, 1),
(2, 1),
(2, 1),
(3, 4),
(3, 4),
(5, 6),
(7, 8),
(7, 6),
(6, 7),
(5, 0)
delete t2
from #t t1
inner join #t t2 on t2.id1 = t1.id2 and t2.id2 = t1.id1
where t2.id1 > t1.id1
select * from #t order by 1, 2
declare #t table (id1 int, id2 int)
insert into #t (id1, id2)
values
(1, 2),
(2, 1),
(3, 4),
(4, 3),
(5, 6),
(6, 5),
(7, 8),
(8, 7)
;
;with a as (
select
row_number() over (order by id1) rn
,t.id1
,t.id2
from
#t t
)
delete t from
#t t
join (
select
a.id1
,a.id2
from
a a
where
exists(
select
*
from
a b
where
a.id2 = b.id1 and a.id1 = b.id2 and a.rn > b.rn
)
) c on t.id1 = c.id1 and t.id2 = c.id2
;
select * from #t;
/* OUTPUT
id1 id2
1 2
3 4
5 6
7 8
*/
It'll vary a little based on which row you want to keep, but if you really have simple duplicates as in your example, and every pair exists in both orders, this should do it:
DELETE FROM MyTable
WHERE ID > ID1
So what i could understand you want to delete the rows from table where id = id1.
delete from TableA as a
where exists(select 1 from TableA as b where a.id = b.id1)

Stick two tables together

Let's consider two tables:
First:
Id Data
1 asd
2 buu
And Second:
UPD:
Id Data
10 ffu
11 fffuuu
10001 asd
I want to get a 4-column table looking like this:
Id1 Data1 Id2 Data2
1 asd 10 fuu
2 buu 11 fffuuu
-1 [any text] 10001 asd
(if the numbers of rows are not equal ,let's use "-1" for the id)
How to do this?
I'm using sqlite3-3.7.3.
UPD2:
There is no matching criteria between tables,any random matching between them will be sufficient for me.
Assuming that the id columns are unique and not null, you can "zip" your tables by:
Creating a row number for each row that corresponds to the
position of the row when the table is ordered by the unique id (as
polishchuk mentioned in his comment); and,
Simulating a FULL OUTER JOIN with 2 LEFT OUTER JOINS.
To demonstrate, I used two tables with differing row counts:
CREATE TABLE foo (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT);
INSERT INTO foo VALUES (NULL, 'a');
INSERT INTO foo VALUES (NULL, 'b');
INSERT INTO foo VALUES (NULL, 'c');
INSERT INTO foo VALUES (NULL, 'd');
INSERT INTO foo VALUES (NULL, 'e');
INSERT INTO foo VALUES (NULL, 'f');
INSERT INTO foo VALUES (NULL, 'g');
INSERT INTO foo VALUES (NULL, 'h');
INSERT INTO foo VALUES (NULL, 'i');
INSERT INTO foo VALUES (NULL, 'j');
DELETE FROM foo WHERE data IN ('b', 'd', 'f', 'i');
CREATE TABLE bar (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT);
INSERT INTO bar VALUES (NULL, 'a');
INSERT INTO bar VALUES (NULL, 'b');
INSERT INTO bar VALUES (NULL, 'c');
INSERT INTO bar VALUES (NULL, 'd');
INSERT INTO bar VALUES (NULL, 'e');
INSERT INTO bar VALUES (NULL, 'f');
INSERT INTO bar VALUES (NULL, 'g');
INSERT INTO bar VALUES (NULL, 'h');
INSERT INTO bar VALUES (NULL, 'i');
INSERT INTO bar VALUES (NULL, 'j');
DELETE FROM bar WHERE data IN ('a', 'b');
To obtain a more readable output, I then ran:
.headers on
.mode column
Then you can execute this SQL statement:
SELECT COALESCE(id1, -1) AS id1, data1,
COALESCE(id2, -1) as id2, data2
FROM (
SELECT ltable.rnum AS rnum,
ltable.id AS id1, ltable.data AS data1,
rtable.id AS id2, rtable.data AS data2
FROM
(SElECT (SELECT COUNT(*) FROM foo
WHERE id <= T1.id) rnum, id, data FROM foo T1
) ltable
LEFT OUTER JOIN
(SElECT (SELECT COUNT(*) FROM bar
WHERE id <= T1.id) rnum, id, data FROM bar T1
) rtable
ON ltable.rnum=rtable.rnum
UNION
SELECT rtable.rnum AS rnum,
ltable.id AS id1, ltable.data AS data1,
rtable.id AS id2, rtable.data AS data2
FROM
(SElECT (SELECT COUNT(*) FROM bar
WHERE id <= T1.id) rnum, id, data FROM bar T1
) rtable
LEFT OUTER JOIN
(SElECT (SELECT COUNT(*) FROM foo
WHERE id <= T1.id) rnum, id, data FROM foo T1
) ltable
ON ltable.rnum=rtable.rnum)
ORDER BY rnum
Which gives you:
id1 data1 id2 data2
---------- ---------- ---------- ----------
1 a 3 c
3 c 4 d
5 e 5 e
7 g 6 f
8 h 7 g
10 j 8 h
-1 9 i
-1 10 j
This works "both ways", for example, if you invert the two tables (foo and bar), you get:
id1 data1 id2 data2
---------- ---------- ---------- ----------
3 c 1 a
4 d 3 c
5 e 5 e
6 f 7 g
7 g 8 h
8 h 10 j
9 i -1
10 j -1