Without using a cursor, I am trying to come up with T-SQL code that would accomplish the following:
On the following table,
SourceData
that has two columns, [ColA] and [ColB], where both are nvarchar(255), with the following example data:
ColA | ColB
==================
AAA | TripleA
TripleA | AAA
AAA | ThreeAs
ThreeAs | AAA
BBB | TripleB
TripleB | BBB
BBB | ThreeBs
ThreeBs | BBB
etc.,
extract the row data into TWO tables,
TableA_Root, and TableB_Children
Where TableA_Root has these columns: [ROID identity], [Root]
and TableB_Children has these columns: [COID identity],[fKey_ROID],[Child]
Such that the resulting table has the example data as such:
TableA_Root
==============
1 | AAA
2 | BBB
TableB_Children
===============
1 | 1 | TripleA
2 | 1 | ThreeAs
3 | 2 | TripleB
4 | 2 | ThreeBs
At first, I thought I would use a Cursor. But, that is not the optimal approach, I am sure. Obviously, this is a sort and merge, which I could do outside of SQL. Some of the ideas I have tried with subqueries using "IN" or "EXISTS" but my attempts are falling short. I could use a fresh perspective.
Assuming there is a primary key on SourceData where you can't have duplicates of the same row then this would get you what you want...
With cte1 As
(
Select Row_Number() Over (Order By ph) As ph,
ColA,
ColB
From (Select 1 As ph,
ColA,
ColB
From SourceData) As n
)
Insert TableA_Root (ROID, Root)
Select Row_Number() Over (Order By c.ph) As ROID,
ColA
From cte1 c
Where Not Exists (Select 1
From cte1 c2
Where c.ColA = c2.ColB
And c.ph > c2.ph);
Insert TableB_Children (COID, ROID, Child)
Select Row_Number() Over (Order By ta.ROID),
ta.ROID,
tb.Colb
From TableA_Root ta
Join SourceData tb
On ta.Root = tb.ColA;
Related
I have a table that looks like that
---------------------------
| id1 | id2 | col1 | col2 |
+-----+-----+------+------+
| 1 | 1 | a | b |
|-----+-----+------+------|
| 1 | 2 | b | c |
|-----+-----+------+------|
| 5 | 1 | d | f |
---------------------------
The idea is that the table stores paths: a->b->c and d->f. What I want is a query that will return a->c and d->f.
You need a recursive query:
with recursive find_path (col1, col2, depth) as (
select col1, col2, 1
from my_table t
where not exists (
select 1
from my_table
where col2 = t.col1)
union all
select p.col1, t.col2, depth+ 1
from my_table t
join find_path p on p.col2 = t.col1
)
select distinct on (col1) format('%s -> %s', col1, col2) as path
from find_path
order by col1, depth desc;
path
--------
a -> c
d -> f
(2 rows)
The question is not quite clear. If your aim is to get the paths in partitions by id1 in order by id2, you can use the window functions:
select distinct on (id1)
id1, first_value(col1) over w, last_value(col2) over w
from my_table
window
w as (partition by id1 order by id2)
order by id1, id2 desc;
id1 | first_value | last_value
-----+-------------+------------
1 | a | c
5 | d | f
(2 rows)
I think you might mean
select a, b, c from whateveryourtablenameis;
and include whatever columns you want in addition to a, b, and c.
This would return just columns a, b, and c. I know of no way to ask SQL for a range of columns other than *.
I have found a lot of examples online of how to remove duplicate rows in a SQL table but I cannot figure out how to remove almost duplicate rows.
Data Example
+--------+----------+--------+
| Col1 | Col2 | NumCol |
+--------+----------+--------+
| USA | Organic | 300 |
| USA | Organic | 400 |
| Canada | Referral | 120 |
| Canada | Referral | 120 |
+--------+----------+--------+
Desired Output
+--------+----------+--------+
| Col1 | Col2 | NumCol |
+--------+----------+--------+
| USA | Organic | 400 |
| Canada | Referral | 120 |
+--------+----------+--------+
In this example, if 2 rows are identical then I would like one of them to be removed. In addition, if 2 rows match based on Col1 and Col2, then I would like the row with the lesser value in NumCol to be removed.
My SQL Server Express code is:
WITH CTE AS(
SELECT [Col1]
,[Col2]
,[NumCol]
, RN = ROW_NUMBER()OVER(PARTITION BY [Col1]
,[Col2]
,[NumCol] ORDER BY [Col1])
FROM table
)
DELETE FROM CTE WHERE RN > 1
This code does a good job of deleting duplicates but it doesn't get rid of rows where only Col1 and Col2 match but not NumCol. How should I approach something like this? I'm a newbie to SQL, so any explanation in layman's terms is appreciated!
You can let the row numbers restart per (Col1, Col2) pair by changing:
RN = ROW_NUMBER()OVER(PARTITION BY [Col1]
,[Col2]
,[NumCol] ORDER BY [Col1])
To:
RN = ROW_NUMBER() OVER(
PARTITION BY Col1, Col1
ORDER BY NumCol desc)
The order by NumCol desc makes sure that the rows with the lower NumCol are removed.
In SQL server, I want to realize that such following manner,
I want to have only resolve SQL
Someone, please tell me.
Table A
col1
---------
AAAAA
BBBBB
CCCCC
DDDDD
EEEEE
Table B
id | col1 | insertDate
------------------
1 | AAAAA | 2015/4/1
2 | BBBBB | 2015/4/1
3 | CCCCC | 2015/4/1
The expected table
(SQL execution: 2015/4/2)
id | col1 | insertDate
------------------
1 | AAAAA | 2015/4/1
2 | BBBBB | 2015/4/1
3 | CCCCC | 2015/4/1
4 | DDDDD | 2015/4/2
5 | EEEEE | 2015/4/2
I want to create a SQL that you can get a table as described above
SQL to extract the record is not in the table A was able to
select
ROW_NUMBER() over(order by col1) as id,
col1,
SYSDATETIME() as insertDate
from A
where
not exists(
select col1
from B
where B.col1 = A.col1
)
Use LEFT JOIN to get all the rows from TableA but only the matching rows from TableB. Then just check if TableB.insertDate IS NULL.
SELECT ROW_NUMBER() OVER (ORDER BY col1) AS id
, col1
, ISNULL(TableB.insertDate, SYSDATETIME()) AS insertDate
FROM TableA
LEFT JOIN TableB
ON TableA.col1 = TableB.col1
Try with this
SELECT ROW_NUMBER() OVER (ORDER BY tablea.col1) AS id
,tablea.col1
,ISNULL(TableB.insertDate, SYSDATETIME()) AS insertDate
FROM TableA
LEFT JOIN TableB
ON TableA.col1 = TableB.col1
(OR)
SELECT ROW_NUMBER() OVER (ORDER BY tablea.col1) AS id
,tablea.col1
,ISNULL(TableB.insertDate, dateadd(day,-1,SYSDATETIME()) )AS insertDate
FROM TableA
LEFT JOIN TableB
ON TableA.col1 = TableB.col1
Hope this will help you.
I have a following task: I have two single column tables in a procedure and both of them have the same amount of rows. I'd like to "merge" them so I get a resulting table with 2 columns. I there some easy way for this?
In worst case I could try to add primary key and use INSERT INTO ... SELECT with JOIN but it requires quite big changes in the code I already have so I decided to ask you guys.
Just to explain my answer below, here's the example. I have following tables:
tableA
col1
----
1
2
3
4
tableB
col2
----
a
b
c
d
Resulting table:
col1 | col2
1 | a
2 | b
3 | c
4 | d
You can do this:
SELECT t1.col1, t2.col1 AS col2
INTO NewTable
FROM
(
SELECT col1, ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RN
FROM table1
) AS t1
INNER JOIN
(
SELECT col1, ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RN
FROM table2
) AS t2 ON t1.rn = t2.rn
This will create a brand new table NewTable with the two columns from the two tables:
| COL1 | COL2 |
---------------
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
See it in action here:
SQL Fiddle Demo.
I have a PresentationSlide table:
PresentationSlide
PresentationSlideId
PresentationId
Content
Order
and example rows:
+---------------------+----------------+---------+-------+
| PresentationSlideId | PresentationId | Content | Order |
+--------+------------+----------------+---------+-------+
| 123 | 3 | "bla" | 1 |
| 23 | 3 | "bla2" | 2 |
| 22 | 3 | "bla3" | 3 |
| 100 | 3 | "bla4" | 4 |
| 150 | 3 | "bla5" | 5 |
+---------------------+----------------+---------+-------+
I want to maintain arithmetic sequence of numbers (1,2,3,4,...) in the Order column after DELETE operation.
For example, if I delete third row (PresentationSlideId = 22), values in order column will be: (1,2,4,5) I want to update Order this way:
PresentationSlideId = 100: update order from 4 to 3
PresentationSlideId = 150: update order from 5 to 4
How is the most efficient way to do this kind of update? Is any way to do this with using only one UPDATE statement? I could do this using cursor and loop, but it doesn't seems efficient.
1) Order is a very poor name for a column, since it's an SQL Keyword
2) It would be a lot better if you could cope with gaps in the order (and possibly switch to using a float, so you can insert fractional values), because in your current model, every insert, update or delete is potentially going to affect the entire table. This doesn't scale well. Computing an order using ROW_NUMBER() during selects would generally be better.
3)
create table #PresentationSlide (
PresentationSlideID int not null,
PresentationId int not null,
Content varchar(10) not null,
[Order] int not null
)
insert into #PresentationSlide (PresentationSlideId , PresentationId , Content , [Order])
select 123,3,'bla',1 union all
select 23,3,'bla2',2 union all
select 22,3,'bla3',3 union all
select 100,3,'bla4',4 union all
select 150,3,'bla5',5
delete from #PresentationSlide where PresentationSlideId = 22
;With Reorder as (select PresentationSlideId,ROW_NUMBER() OVER (ORDER BY [Order]) as NewOrder from #PresentationSlide)
update ps set [Order] = NewOrder
from #PresentationSlide ps inner join Reorder r on ps.PresentationSlideId = r.PresentationSlideId
select * from #PresentationSlide order by [Order]
drop table #PresentationSlide
;with C as
(
select [Order],
row_number() over(order by [Order]) as rn
from PresentationSlide
)
update C set
[Order] = rn