SQL expand row mapping every grouped value to a coordinated value - sql

I have a table, where I'm doing some iterative calculations for an engineering application. ColD has been calculated from another query, so it's basically trying to find a best fit. Part of the strategy in the best fit, is to get a point where I look at each grouping of ColC (grouping signified by ColB), and have each value reference the value in ColD.
In essence, I need Table A to be converted to Table B
Table A:
ColA ColB ColC ColD
1 1 A 200
2 2 B 300
3 3 C 400
4 1 X 200
5 2 Y 400
6 3 Z 600
Table B:
A 200
B 200
C 200
A 300
B 300
C 300
A 400
B 400
C 400
X 200
Y 200
Z 200
X 400
Y 400
Z 400
X 600
Y 600
Z 600

It looks like you want something like this:
WITH cte
AS
(
SELECT
ColA
, ColB
, ColC
, ColD
, SUM(CASE WHEN L < ColB THEN 0 ELSE 1 END) OVER (ORDER BY ColA) GroupID
FROM
(
SELECT
ColA
, ColB
, ColC
, ColD
, LAG(ColB, 1, NULL) OVER (ORDER BY ColA) L
FROM YourTable
) Q
)
SELECT
C1.ColC
, C2.ColD
FROM
cte C1
JOIN cte C2 ON C1.GroupID = C2.GroupID
ORDER BY C2.ColA

Related

The way for insert and fill table base on column in another table in sql with Several million rows

I have a table similar A With 2 million recordes
ROW ID ITEM NoOfUnit
1 1 A 2
2 2 B 1
3 3 C 3
.
.
.
I want fill table B base on NoOfUnit from A Similar to the below
ROW ID ITEM QTY
1 1 A 1
2 1 A 1
3 2 B 1
4 3 C 1
5 3 C 1
6 3 C 1
.
.
.
Number of rows in table B very large and cursor very slow...
I would just use a recursive CTE:
with cte as (
select id, item, NoOfUnit, 1 as n
from a
union all
select id, item, NoOfUnit, n + 1
from a
where n < NoOfUnit
)
insert into b (id, item, qty)
select id, item, 1
from cte;
If qty is ever greater than 100, then you need option (maxrecursion 0).
All you need to do here is duplicate your rows based on the number held in NoOfUnit, which you could do with a numbers table. You then insert the result of this into your destination table.
An example of how to do this is as follows:
Query
declare #d table(ID int, ITEM char(1),NoOfUnit int);
insert into #d values
(1,'A',2)
,(2,'B',1)
,(3,'C',3)
;
with t as(select t from(values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) as t(t)) -- table with 10 rows
,n as(select row_number() over (order by (select null)) as n from t,t t2,t t3,t t4,t t5) -- cross join 10 rows 5 times for 10 * 10 * 10 * 10 * 10 = 100,000 rows with incrementing value
select d.ID
,d.ITEM
,1 as QTY
from #d as d
join n
on d.NoOfUnit >= n.n
order by d.ID
,d.ITEM;
Output
ID
ITEM
QTY
1
A
1
1
A
1
2
B
1
3
C
1
3
C
1
3
C
1

Oracle SQL: Transfer certain records from one table to another filtering rows based on condition

Need to transfer certain records of some columns from Table1 to Table2 but filtering rows based on condition.
Lets say Table1 looks like as shown below, has many columns in it.
Table1
A B C D E F G H ...
1 24-OCT-20 08.22.57.642000000 AM 100 xyz 1 1
2 24-OCT-20 08.22.57.642000000 AM 100 xyz 1 0
13 25-OCT-20 05.47.52.733000000 PM 100 xyz 1 0
34 26-OCT-20 09.22.57.642000000 AM 100 xyz 1 0
25 26-OCT-20 09.25.57.642000000 AM 101 xyz 1 0
26 26-OCT-20 09.25.57.642000000 AM 101 xyz 1 1
6 26-OCT-20 09.25.57.642000000 AM 101 abc 1 1
10 26-OCT-20 09.25.57.642000000 AM 101 xyz 0 1
17 26-OCT-20 04.22.57.642000000 AM 100 xyz 1 0
18 26-OCT-20 06.22.57.642000000 AM 105 xyz 1 1
19 26-OCT-20 06.22.57.642000000 AM 105 xyz 1 0
In Table2, need to insert rows from Table1 based on following:
First, select A, B, C, D, E, F from Table1 where D='xyz' and E=1; and on the result of this query apply the following condition to further filter out unwanted rows:
Condition: For same values in columns B, C, D & E in 2 different rows, if column F has 2 different values then only keep the row with greater value in column A.
So desired output in Table2 is shown as below:
Table2
A B C D E F
2 24-OCT-20 08.22.57.642000000 AM 100 xyz 1 0
13 25-OCT-20 05.47.52.733000000 PM 100 xyz 1 0
34 26-OCT-20 09.22.57.642000000 AM 100 xyz 1 0
26 26-OCT-20 09.25.57.642000000 AM 101 xyz 1 1
17 26-OCT-20 04.22.57.642000000 AM 100 xyz 1 0
19 26-OCT-20 06.22.57.642000000 AM 105 xyz 1 0
How can this be achieved through the simplest and most efficient SQL query?
Any help will be appreciated.
You can use window functions:
insert into table2 (a, b, c, d, e, f)
select a, b, c, d, e, f
from (
select t1.*,
row_number() over(partition by b, c, d, e order by a desc) rn
from table1 t1
where d = 'xyz' and e = 1
) t1
where rn = 1
This can be achieved using the GROUP BY and KEEP clause as follows:
select max(t.a) as a, t.b, t.c, t.d, t.e,
max(t.f) keep (dense_rank last over order by t.a) as f
from t
where t.d = 'xyz' and t.e = 1
group by t.b, t.c, t.d, t.e

Case when statement with summed values in SQL

I have a dataset with two columns. I want to categorise one of the columns into bins, and then sum the values in the other column that are within each bin.
I have tried the following code
select DISTINCT (
CASE WHEN H=1 THEN '1'
WHEN H BETWEEN 2 AND 3 THEN '2-3'
WHEN H BETWEEN 4 AND 6 THEN '4-6'
ELSE '' END
) AS H , sum(V) [V]
from
TABLE1 inner join TABLE 2 on TABLE1.X=TABLE2.X
where
TABLE.X=1 and Y='id'
GROUP BY H
ORDER BY H ASC
The table below gives a sample of my data (where H and V are headers)
H V
1 100
1 1000
1 1500
2 300
3 500
4 9000
5 800
6 1100
My desired output is
H V
1 2600
2 TO 3 800
4 TO 6 10900
However, I am getting (ie. duplicated bins as column V is not being summed across all values in each bin)
H V
1 100
1 1000
1 1500
2-3 300
2-3 500
4-6 9000
4-6 800
4-6 1100
You seem to want aggregation on a computed column:
select (CASE WHEN H = 1 THEN '1'
WHEN H BETWEEN 2 AND 3 THEN '2-3'
WHEN H BETWEEN 4 AND 6 THEN '4-6'
ELSE ''
END) AS H , sum(V) as V
from TABLE1 inner join
TABLE2
on TABLE1.X = TABLE2.X
where TABLE.X = 1 and Y = 'id'
GROUP BY (CASE WHEN H = 1 THEN '1'
WHEN H BETWEEN 2 AND 3 THEN '2-3'
WHEN H BETWEEN 4 AND 6 THEN '4-6'
ELSE ''
END)
ORDER BY MIN(H) ASC;
You should qualify all column references in the query.
SELECT DISTINCT is almost never appropriate with GROUP BY.

Clause ORDER BY

I have a problem with a select in sql server, i have this table with 2 columns:
a 2
b 1
c 100
d 1
a 100
b 1
c 2
d 1
I want ordered it based on the first column,in this way:
a 2
a 100
b 1
b 1
c 2
c 100
d 1
d 1
But then j want the rows with secondcolumn=100 be moved at the bottom,so:
a 2
b 1
b 1
c 2
d 1
d 1
a 100
c 100
I have tried with clause ORDER BY column1 ASC, (column2=100) ASC,but it didnt work!
Thankyou and greetings.
Actually, you want the rows with 100 in the second column moved to the bottom first, and then ordered by the first column:
order by (case when col2 = 100 then 1 else 0 end),
col1
Use the CASE expression as below
SELECT *
FROM tab
ORDER BY CASE
WHEN column2 = 100 THEN 1
ELSE 0
END ASC,
column1 asc
SELECT *
FROM table1
ORDER BY
CASE
WHEN col2>=100 THEN 1
ELSE 0
END,
col1,
col2
SQLFiddle Example

An sql statement to select the closest values

In the table below, that I'll call TableA are two numerical columns. I need to create a Select statement whereby the value of B is specified. Either one or two rows are returned. Not sure if this can be done in a single sql statement. If a row exists where the value of B matches, then just that row is returned. If the value of B is between two values of B that are closest to its value, both values are returned. If a value exists that is larger than it but no value exists that is smaller than it, than the larger value is returned. If no larger value exists but a smaller one does, than the row with the smaller value is returned. Here are some examples. It would be nice if the sql worked in sqlite:
A B
50 400
10 200
30 100
40 800
20 500
B = 10
A B
30 100
----------
B = 250
A B
10 200
50 400
----------
B = 100
A B
30 100
----------
B = 410
A B
50 400
20 500
----------
B = 900
A B
40 800
SELECT * FROM A WHERE B = 10
UNION
SELECT * FROM A WHERE B = (SELECT MAX(B) FROM A WHERE B < 10)
UNION
SELECT * FROM A WHERE B = (SELECT MIN(B) FROM A WHERE B > 10);
See it working live in an sqlfiddle.
SELECT * FROM TableA WHERE B = (SELECT MAX(B) FROM TableA WHERE B <= 10)
UNION
SELECT * FROM TableA WHERE B = (SELECT MIN(B) FROM TableA WHERE B >= 10)