How can i remove rows from several tables with SQL? - sql

I have a 3 tables:
mainTable:
id | uniqField
--------------
1 | 1111
2 | 1111
3 | 2222
4 | 2222
5 | 3333
6 | 4444
table1:
id|name|deleted
----------
1|Mike|0
2|Mike|0
5|John|0
table2:
id|name|deleted
----------
3|Peke|0
4|Peke|0
6|Vels|0
That tables bind by id field.
Now i want to remove duplicates from this tables. For mainTable i can use:
DELETE mainTable
FROM mainTable
LEFT OUTER JOIN (
SELECT MIN(id) as RowId, uniqField
FROM mainTable
GROUP BY uniqField
) as KeepRows ON
mainTable.id= KeepRows.RowId
WHERE
KeepRows.RowId IS NULL
But in tables1 and table2 i want to set deleted field to 0->1 to duplicates I mean:
1 | 1111
2 | 1111 -> duplicate->remove
1|Mike|0
2|Mike|0->duplicate-> 0->1

Try this one -
SET NOCOUNT ON;
DECLARE #mainTable TABLE
(
id INT,
uniqField INT
)
INSERT INTO #mainTable (id, uniqField)
VALUES (1, 1111), (2, 1111), (3, 2222), (4, 2222), (5, 3333), (6, 4444)
DECLARE #deleted TABLE (id INT)
;WITH cte AS
(
SELECT *, RowNum = ROW_NUMBER() OVER (PARTITION BY uniqField ORDER BY 1/0)
FROM #mainTable
)
DELETE FROM cte
OUTPUT DELETED.id INTO #deleted
WHERE RowNum > 1
DECLARE #table1 TABLE
(
id INT,
uniqField VARCHAR(10),
deleted BIT
)
DECLARE #table2 TABLE
(
id INT,
uniqField VARCHAR(10),
deleted BIT
)
INSERT INTO #table1 (id, uniqField, deleted)
VALUES (1, 'Mike', 0), (2, 'Mike', 0), (5, 'John', 0)
INSERT INTO #table2 (id, uniqField, deleted)
VALUES (3, 'Peke', 0), (4, 'Peke', 0), (6, 'Vels', 0)
UPDATE #table1
SET deleted = 1
FROM #deleted
WHERE [#deleted].id = [#table1].id
UPDATE #table2
SET deleted = 1
FROM #deleted
WHERE [#deleted].id = [#table2].id
SELECT * FROM #table1
SELECT * FROM #table2
Output -
id uniqField deleted
----------- ---------- -------
1 Mike 0
2 Mike 1
5 John 0
id uniqField deleted
----------- ---------- -------
3 Peke 0
4 Peke 1
6 Vels 0

Related

Update OrderID based on the Select Order By Results?

I am using SQLite 3. I have a table MyTable, as follows:
Create table mytable (ID as INTEGER, OrderID as INTEGER, a as INTGER, b as INTEGER);
Insert into mytable (ID, OrderID,a,b) values (1, 1,1,1);
Insert into mytable (ID, OrderID,a,b) values (1, 2,1,2);
Insert into mytable (ID, OrderID,a,b) values (2, 1,1,3);
Insert into mytable (ID, OrderID,a,b) values (2, 3,2,1);
Insert into mytable (ID, OrderID,a,b) values (3, 1,2,3);
Now if I using the following statement:
Select * from mytable ORDER BY a desc, b desc;
I will get all rows in a different order, as follows:
(3, 1, 2, 3);
(2, 3, 2, 1);
(2, 1, 1, 3);
(1, 2, 1, 2);
(1, 1, 1, 1);
Now I want to update the order ID to the sequence number of the rows appear in the above results, as follows:
(3, 1, 2, 3);
(2, 2, 2, 1);
(2, 3, 1, 3);
(1, 4, 1, 2);
(1, 5, 1, 1);
How to do so?
Try This :-
Select ROW_NUMBER() OVER (ORDER BY (SELECT 1 ) ) AS ordNo, * INTO #TempTable from
mytable ORDER BY a desc, b desc;
UPDATE mytable SET OrderID = ordNo FROM #TempTable WHERE mytable.ID
=#TempTable.ID AND mytable.a=#TempTable.a AND mytable.b=#TempTable.b
Assuming that the a and b values are unique:
update mytable t
set orderid = (select count(*)
from mytable t2
where t2.a > t.a or
(t2.a = t.a and t2.b >= t.b)
);
There is a column [rowid][1] responsible for every rowid
Most tables in a typical SQLite database schema are rowid tables.
Rowid tables are distinguished by the fact that they all have a unique, non-NULL, signed 64-bit integer rowid that is used as the access key for the data in the underlying B-tree storage engine.
Due to old SQLite version didn't support ROW_NUMBER window function, you can use a subquery in select to make it.
You can try to use correlated subquery and UPDATE by rowid.
Schema (SQLite v3.18)
Create table mytable (ID INT, OrderID INT, a INT, b INT);
Insert into mytable (ID, OrderID,a,b) values (1, 1,1,1);
Insert into mytable (ID, OrderID,a,b) values (1, 2,1,2);
Insert into mytable (ID, OrderID,a,b) values (2, 1,1,3);
Insert into mytable (ID, OrderID,a,b) values (2, 3,2,1);
Insert into mytable (ID, OrderID,a,b) values (3, 1,2,3);
update mytable
set orderid=
(
SELECT (select count(*)
from mytable tt
where tt.a > t1.a or
(tt.a = t1.a and tt.b >= t1.b)) rn
FROM mytable t1
where mytable.rowid=t1.rowid
);
Query #1
SELECT * FROM mytable order by OrderID;
| ID | OrderID | a | b |
| --- | ------- | --- | --- |
| 3 | 1 | 2 | 3 |
| 2 | 2 | 2 | 1 |
| 2 | 3 | 1 | 3 |
| 1 | 4 | 1 | 2 |
| 1 | 5 | 1 | 1 |
View on DB Fiddle

SQL Server 2008 Select all columns of a table + a column from the same table based on a column value

I have a table VERSION with composite keys docId, verId:
docId verId apprvDt old_verId
------ ------ ----------- ----------
A 3 03/20/2017 2
A 2 03/18/2017 1
A 1 03/16/2017 null
B 1 03/18/2017 null
C 2 03/20/2017 1
C 1 03/16/2017 null
Say I select docId=A, verId=3, query should return
docId verId apprvDt old_verId old_apprvDt
------ ------ ----------- ---------- ------------
A 3 03/20/2017 2 03/18/2017
that is to retrieve the apprvDt of the old_verId.
I tried like this
select a.docId, a.verId, a.apprvDt, a.old_verId, b.old_apprvDt
from VERSION as a left join
(select x.docId, x.verId, x.apprvDt as old_apprvDt from REVISN as x
where x.docId = 'A' and x.verId = a.old_verId) as b
on b.docId = a.docId and b.verId = a.old_verId
but I am getting a multi-part binding error.
I want to select a row from VERSION including the apprvDt (old_apprvDt) of old_verId
Solution to your problem is as given below :
DECLARE #tbl TABLE(docId varchar(100), verId int, apprvDt datetime, old_verId int)
insert into #tbl values('A', 3 , '03/20/2017', 2)
insert into #tbl values('A', 2 , '03/18/2017', 1)
insert into #tbl values('A', 1 , '03/16/2017', NULL)
insert into #tbl values('B', 1 , '03/18/2017', NULL)
insert into #tbl values('C', 2 , '03/20/2017', 1)
insert into #tbl values('C', 1 , '03/16/2017', NULL)
select * from #tbl
;with data_table
as
(
select docId,verId,apprvDt,old_verId,
(select apprvDt from #tbl T2 where T2.docId=t1.docid and T2.verId=t1.old_verId)
old_apprvDt from #tbl t1
)
select * from data_table where docId='A' and verId=3
Result is as below :
-------------------------------------------------------------------------------------
docId verId apprvDt old_verId old_apprvDt
-------------------------------------------------------------------------------------
A 3 2017-03-20 00:00:00.000 2 2017-03-18 00:00:00.000
select t1.*,
b.apprvdt as old_apprvdt
from table1 t1
cross apply
(
select apprvdt from table1 t2 where t1.docid=t2.docid
and t2.old_verid =t1.verid ) b

select if field match or if child record field match

I have a table Cities as
(Id, Name, ParentId)
where ParentId is the Id of a City (self related table)
I want to get the cities wheres the parentId is null (root)
if the name matches or child record name matches I wrote this
declare #cities table (Id, Name, ParentId)
insert into #cities (Id , Name)
select Id , Name from Cities
Where CHARINDEX(N'CD', Name) > 0 and ParentId is null
insert into #cities (Id , Name)
select Id , Name from Cities
Where Id in
(select distinct ParentId from Cities
where CHARINDEX(N'CD', Name) > 0 ParentId is not null)
and ParentId is null
select distinct * from #cities
What can I do to make it faster and better?
Edit:
Id | Name | ParentId
----------------------
1 | ABCD | NULL
----------------------
2 | EFZX | NULL
----------------------
3 | GHIJ | NULL
----------------------
4 | MNOP | 1
----------------------
5 | CDKL | 2
----------------------
6 | QRST | 3
----------------------
this should return:
Id | Name | ParentId
----------------------
1 | ABCD | NULL
----------------------
2 | EFZX | NULL
----------------------
Edit2:
the first select returns the cities with matching names
the second select returns the cities with matching children
then merge the two results.
I can suggest solution with one select.
I have considered that you want result by parents and also by immediate descendants. So you should select all rows where name matches 'CD'
SELECT * FROM #cities
WHERE CHARINDEX(N'CD', Name) > 0
This will give you
1 ABCD NULL
5 CDKL 2
6 CDKP 2
You want select only parents, that's why you need left join on parent to take rows where parent is 2
SELECT * FROM #cities c1
LEFT JOIN #cities c2 ON c1.ParentId = c2.ID
WHERE CHARINDEX(N'CD', c1.Name) > 0
This returns
1 ABCD NULL NULL NULL NULL
5 CDKL 2 2 EFZX NULL
6 CDKP 2 2 EFZX NULL
Then you apply second where and (c1.ParentId is NULL OR (c1.ParentId IS NOT NULL AND c2.ParentId IS NULL)) to take parents and immediate descendants only.
declare #cities table (Id int, Name NVARCHAR(MAX), ParentId INT null)
INSERT INTO #cities (Id, Name, ParentId) VALUES (1, 'ABCD', NULL)
INSERT INTO #cities (Id, Name, ParentId) VALUES (2, 'EFZX', NULL)
INSERT INTO #cities (Id, Name, ParentId) VALUES (3, 'GHIJ', NULL)
INSERT INTO #cities (Id, Name, ParentId) VALUES (4, 'MNOP', 1)
INSERT INTO #cities (Id, Name, ParentId) VALUES (5, 'CDKL', 2)
INSERT INTO #cities (Id, Name, ParentId) VALUES (6, 'CDKP', 2)
SELECT DISTINCT ISNULL(c2.Id, c1.Id), ISNULL(c2.Name, c1.Name) FROM #cities c1
LEFT JOIN #cities c2 ON c1.ParentId = c2.ID
WHERE CHARINDEX(N'CD', c1.Name) > 0 and (c1.ParentId is NULL OR (c1.ParentId IS NOT NULL AND c2.ParentId IS NULL))
SAMPLE CODE
CREATE table #cities (Id INT, Name VARCHAR(30), ParentId INT)
insert into #cities (Id, Name, ParentId) VALUES(1 , 'ABCD',NULL)
insert into #cities (Id, Name, ParentId) VALUES(2 , 'EFZX',NULL)
insert into #cities (Id, Name, ParentId) VALUES(3 , 'GHIJ',NULL)
insert into #cities (Id, Name, ParentId) VALUES(4 , 'MNOP',1)
insert into #cities (Id, Name, ParentId) VALUES(5 , 'CDKL',2)
insert into #cities (Id, Name, ParentId) VALUES(6 , 'QRST',3)
QUERY
;WITH CTE AS
(
-- Select condition for parent
SELECT Id, Name, ParentId,0 AS [LEVEL]
FROM #cities --WHERE ParentId IS NULL --AND ID=1
WHERE CHARINDEX(N'CD', Name) > 0 and ParentId is null
UNION ALL
SELECT C1.*,C2.[LEVEL]+1
FROM #cities C1
JOIN CTE C2 ON C1.ParentId=C2.Id
)
-- Since you get only parent and children, you can filter children here
SELECT *
FROM CTE
WHERE CHARINDEX(N'CD', Name) > 0
OPTION(MAXRECURSION 0)

SQL : how to find leaf rows?

i have a self related table myTable like :
ID | RefID
----------
1 | NULL
2 | 1
3 | 2
4 | NULL
5 | 2
6 | 5
7 | 5
8 | NULL
9 | 7
i need to get leaf rows on any depth
based on the table above, the result must be :
ID | RefID
----------
3 | 2
4 | NULL
6 | 5
8 | NULL
9 | 7
thank you
PS: the depth may vary , here is very small example
Try:
SELECT id,
refid
FROM mytable t
WHERE NOT EXISTS (SELECT 1
FROM mytable
WHERE refid = t.id)
DECLARE #t TABLE (id int NOT NULL, RefID int NULL);
INSERT #t VALUES (1, NULL), (2, 1), (3, 2), (5, NULL),
(6, 5), (4, NULL), (7, 5), (8, NULL), (9, 8), (10, 7);
WITH CTE AS
(
-- top level
SELECT id, RefID, id AS RootId, 0 AS CTELevel FROM #t WHERE REfID IS NULL
UNION ALL
SELECT T.id, T.RefID, RootId, CTELevel + 1 FROM #t T JOIN CTE ON T.RefID = CTE.id
), Leafs AS
(
SELECT
id, RefID, DENSE_RANK() OVER (PARTITION BY CTE.RootId ORDER BY CTELevel DESC) AS Rn
FROM CTE
)
SELECT
id, RefID
FROM
Leafs
WHERE
rn = 1
select ID, RefId
from myTable t1 left join myTable t2 on t1.ID = t2.RefID
where t2.RefID is null
try this:
SELECT *
FROM
my_table
WHERE
id NOT IN
(
SELECT DISTINCT
refId
FROM
my_table
WHERE
refId IS NOT NULL
)

merging rows into 1 column

I have a table with 2 columns
Input
Col 1 ---- Col 2
1 ---- aaaa
1 ---- bbbb
1 ---- cccc
2 ---- dddd
2 ---- eeee
2 ---- ffff
2 ---- gggg
Output
Col 1 ---- Col 2
1 ---- aaaabbbbcccc
2 ---- ddddeeeeffffgggg
I was thinking of doing several self joins, but doesnt seem efficient. Any ideas on how the sql has to be written?
Ok, I'll bite. Instead of stragg, try listagg (in 11.2):
create table tst1
(
pid number,
val varchar2(10)
);
insert into tst1 values(1, 'Rec1');
insert into tst1 values(1, 'Rec2');
insert into tst1 values(1, 'Rec3');
insert into tst1 values(2, 'Rec1');
insert into tst1 values(2, 'Rec2');
commit;
select pid, listagg(val, ':') within group(order by val) as "The List"
from tst1
group by pid;
And you get:
pid The List
1 Rec1:Rec2:Rec3
2 Rec1:Rec2
If you change the order by to "order by val desc" you'd get
pid The List
1 Rec3:Rec2:Rec1
2 Rec2:Rec1
This is a version that will work in Oracle 9i and up.
create table foo (
key_column number,
val_column varchar2(4)
);
insert into foo values (1, 'aaaa');
insert into foo values (1, 'bbbb');
insert into foo values (1, 'cccc');
insert into foo values (2, 'dddd');
insert into foo values (2, 'eeee');
insert into foo values (2, 'ffff');
insert into foo values (2, 'gggg');
select key_column
, replace(max(sys_connect_by_path(val_column, ',')), ',') combined
from (select key_column
, val_column
, row_number() over (partition by key_column order by val_column) cur
, row_number() over (partition by key_column order by val_column) - 1 prev
from foo) foo
group by key_column
connect by prior cur = prev and prior key_column = key_column
start with cur = 1;
key_column | val_column
--------------------------
1 | aaaabbbbcccc
2 | ddddeeeeffffgggg