Group value via range and value sql query - sql-server

I have two table .
Table1 have following fields.
From To id
---- ---- ----
0 0 1
1 5 2
5 10 3
10 15 4
Table 2:
Table 1 ID Value
--------- -------
1 10
2 10
3 15
4 10
current output:
from To Value
----- ------ -------
0 15 10
5 10 15
Required Output
From To Value
------ ---- ------
0 5 10
5 10 15
10 15 10
How get the output like
code
SELECT MIN(DiscountFrom) FromDiscount ,
MAX(DiscountTo) Todiscount ,
Amount
FROM table1 t1
JOIN table2 t2 ON t1.id = t2.id
GROUP BY Amount

Here for me grouping makes no sense so, i used lead() function to access next record if 0 found
select distinct
case when t.[from] = 1 then 0 else t.[from] end [from],
case when t.[to] = 0 then lead(t.[to]) over (order by t.id) else t.[to] end [to],
t1.value
from table1 t
join table2 t1 on t1.id = t.id
Result :
from to value
0 5 10
5 10 15
10 15 10

It looks like your data is inconsistent, for this to work i had to change the first record to
From To id
---- ---- ----
0 1 1
then this works for all cases
;WITH test1
AS (SELECT
t.id
,[from]
,[to]
,value
FROM
table1 t
JOIN table2 t1
ON t1.id = t.id),
MyTest
AS (SELECT
Anchor.[from]
,Anchor.[To]
,Anchor.value
,1 AS Grp
FROM
test1 AS Anchor
WHERE
[From] = 0
UNION ALL
SELECT
Child.[from]
,Child.[To]
,Child.value
,CASE WHEN Mytest.value = child.value THEN 0 ELSE 1 END + MyTest.Grp AS grp
FROM
test1 AS Child
INNER JOIN MyTest
ON Mytest.[To] = child.[From])
SELECT
Min([From]) AS [From]
,Max([To]) AS [To]
,Max(Value) AS Value
FROM
mytest
GROUP BY
Grp

Related

Compare two tables and retrieve data

I have 2 tables in SQL Server and I want to compare them. I want to take 'NEEDED_AMOUNT' and 'min. 'ID'. I tried the following:
SELECT S_ID, NEEDED_AMOUNT, ID
FROM (
select T1.S_ID
, T2.NEEDED_AMOUNT
, T1.ID
from T1
INNER JOIN T2 MSD ON T1.S_ID = T2.S_ID
) TABLE1
GROUP BY S_ID, NEEDED_AMOUNT, ID
To explain this for example: in T1 table I have S_ID as '1' and its amount '20' and '30'. Also in T2 I have request for S_ID and I need '40' amount. So in T1 table how can I reach 40? I must take first row '20' amount and I split second row '30' to '20'. Below you can see what I want the output.
So here are the tables.
I can call this table T1 (ID is primary key and auto inc.):
ID AMOUNT S_ID
1 20 1
2 30 1
3 10 2
4 20 3
5 5 3
and I can call this table T2:
S_ID NEEDED_AMOUNT DATE
1 40 01.01.2020
2 5 02.01.2020
3 20 03.01.2020
So my output will be like this:
S_ID NEEDED_AMOUNT ID
1 20 1
1 20 2
2 5 3
3 20 4
Thanks for any opinion
I would use recursive approach for this :
with cte as (
select id, amount, s_id, needed_amount,
(case when amount = needed_amount then 1 else cnt end) as cnt
from (select t1.*, t2.needed_amount,
row_number() over (partition by t1.s_id order by t1.id) as seq,
count(*) over (partition by t1.s_id) as cnt
from t1 inner join
t2
on t2.s_id = t1.s_id
) t
where seq = 1
), cte1 as (
select c.needed_amount / c.cnt as amount, c.s_id, 1 as start, c.cnt
from cte c
union all
select amount, s_id, start + 1, cnt
from cte1 c1
where start < cnt
)
select s_id, amount, row_number() over (order by s_id) as id
from cte1;

Return rows that have a negative equivalent

I have a non-normalized table with several columns. I would like to return all columns that have a positive number along with a negative number of the same value.
Example:
ID | Value
-------------
1 | 10
1 | -10
3 | 15
3 | 15
4 | -1
5 | 4
Current Output:
ID | Values
-------------
1 | 10
1 | -10
3 | 15
3 | 15
Desired Output:
ID | Value
-------------
1 | 10
1 | -10
I have made a windows function as seen below that will select absolute values that are the same, but this includes pairs where there are a positive number.
select Count(*) Over (Partition By DVN, [Tran Date], [Reference Number],Description,Vendor, Abs([Maintenance Expense])) As cnt , *
From WorkTemp.dbo.Customer2700Combine
Where [Maintenance Expense] Is Not Null
Order By 1 Desc,DVN, [Tran Date], [Reference Number],Description,Vendor, Abs([NonRental Total])
Not sure if your requirement is by [ID], looking at your example, description and desired output, this is how I would do it:
DROP TABLE IF EXISTS #sopg;
SELECT [ID],
[VALUE]
INTO #sopg
FROM
(
SELECT 1 AS ID,
10 AS VALUE
UNION
SELECT 1 AS ID,
-10 AS VALUE
UNION
SELECT 3 AS ID,
15 AS VALUE
UNION
SELECT 3 AS ID,
15 AS VALUE
UNION
SELECT 4 AS ID,
-1 AS VALUE
UNION
SELECT 5 AS ID,
4 AS VALUE
) x;
-- Assuming that one ID can only have maximum 2 rows (like your example above) and want this by ID
SELECT s.[ID],
s.[VALUE]
FROM #sopg s
INNER JOIN
(
SELECT ID,
SUM(VALUE) SumZero
FROM #sopg
GROUP BY ID
HAVING SUM(VALUE) = 0
) SumZero ON SumZero.ID = s.ID
-- Another way, assuming that ID can have more than 2 rows and different values
DROP TABLE IF EXISTS #sopg2;
SELECT [ID],
[VALUE]
INTO #sopg2
FROM
(
SELECT 1 AS ID,
10 AS VALUE
UNION
SELECT 1 AS ID,
-10 AS VALUE
UNION
SELECT 1 AS ID,
-9 AS VALUE
UNION
SELECT 3 AS ID,
15 AS VALUE
UNION
SELECT 3 AS ID,
15 AS VALUE
UNION
SELECT 4 AS ID,
-1 AS VALUE
UNION
SELECT 5 AS ID,
4 AS VALUE
) x
SELECT a.[ID],
a.[VALUE]
FROM #sopg2 a
INNER JOIN #sopg b ON b.ID = a.ID AND a.VALUE = -b.VALUE

ORACLE Join table to select multiple record in 1 row

I have 2 tables
TableA: Main table with 1 record for each Field called ID
TableB: Can contain multiple record for field called ID
I want to select everything based on ID from TableA and TableB in 1 line for the end result
Example
Sample Records
From TableA
ID Name Address
--- ---- ----------
1 Jack 123 blahST
2 John 234 blahAVE
321 Sam 2123 blahWay
From TableB
ID AccNO
-- -------------
1 12345
1 345345
1 443453
2 99999
3 88888
3 77777
End Result should be like
Select TableA.ID,
TableA.Name,
TableA.Address,
TableB.ID,
TableB.AccNO1,
TableB.AccNO2, --if it exist
TableB.AccNO3, --if it exist
TableB.AccNO4, --if it exist MAX
From TableA Full Outer Join TableB on TableB.ID = TableA.ID
TableA.ID TableA.Name TableA.Address TableB.ID TableB.AccNO TableB.AccNO2 TableB.AccNo3,TableB.AccNo4
--------- ----------- -------------- --------- ------------ ------------- ------------- -------------
1 Jack 123 Blahst 1 12345 345345 443453
2 John 234 BlahAVE 2 99999
3 Sam 2123 Blahway 3 88888 7777777
Here are a couple of ways of doing it - one using the PIVOT keyword available in 11g and above, the other using the old-style pivot using MAX() and group by.
Method 1:
with tablea as (select 1 id, 'Jack' name, '123 blahST' address from dual union all
select 2 id, 'John' name, '234 blahAVE' address from dual union all
select 3 id, 'Sam' name, '2123 blahWay' address from dual),
tableb as (select 1 id, 12345 accno from dual union all
select 1 id, 345345 accno from dual union all
select 1 id, 443453 accno from dual union all
select 2 id, 99999 accno from dual union all
select 3 id, 88888 accno from dual union all
select 3 id, 77777 accno from dual),
b_res as (select *
from (select id,
accno,
row_number() over (partition by id order by accno) rn
from tableb)
pivot (max(accno)
for rn in (1 as accno1,
2 as accno2,
3 as accno3,
4 as accno4,
5 as accno5)))
select ta.id ta_id,
ta.name ta_name,
ta.address ta_address,
tb.id tb_id,
tb.accno1 tb_accno1,
tb.accno2 tb_accno2,
tb.accno3 tb_accno3,
tb.accno4 tb_accno4,
tb.accno5 tb_accno5
from tablea ta
inner join b_res tb on ta.id = tb.id;
TA_ID TA_NAME TA_ADDRESS TB_ID TB_ACCNO1 TB_ACCNO2 TB_ACCNO3 TB_ACCNO4 TB_ACCNO5
---------- ------- ------------ ---------- ---------- ---------- ---------- ---------- ----------
1 Jack 123 blahST 1 12345 345345 443453
2 John 234 blahAVE 2 99999
3 Sam 2123 blahWay 3 77777 88888
Method 2:
with tablea as (select 1 id, 'Jack' name, '123 blahST' address from dual union all
select 2 id, 'John' name, '234 blahAVE' address from dual union all
select 3 id, 'Sam' name, '2123 blahWay' address from dual),
tableb as (select 1 id, 12345 accno from dual union all
select 1 id, 345345 accno from dual union all
select 1 id, 443453 accno from dual union all
select 2 id, 99999 accno from dual union all
select 3 id, 88888 accno from dual union all
select 3 id, 77777 accno from dual),
b_res as (select id,
max(case when rn = 1 then accno end) accno1,
max(case when rn = 2 then accno end) accno2,
max(case when rn = 3 then accno end) accno3,
max(case when rn = 4 then accno end) accno4,
max(case when rn = 5 then accno end) accno5
from (select id,
accno,
row_number() over (partition by id order by accno) rn
from tableb)
group by id)
select ta.id ta_id,
ta.name ta_name,
ta.address ta_address,
tb.id tb_id,
tb.accno1 tb_accno1,
tb.accno2 tb_accno2,
tb.accno3 tb_accno3,
tb.accno4 tb_accno4,
tb.accno5 tb_accno5
from tablea ta
inner join b_res tb on ta.id = tb.id;
TA_ID TA_NAME TA_ADDRESS TB_ID TB_ACCNO1 TB_ACCNO2 TB_ACCNO3 TB_ACCNO4 TB_ACCNO5
---------- ------- ------------ ---------- ---------- ---------- ---------- ---------- ----------
1 Jack 123 blahST 1 12345 345345 443453
2 John 234 blahAVE 2 99999
3 Sam 2123 blahWay 3 77777 88888

How to select PIVOT for this table?

I have a table like this:
Id Code Value
----------- -------------------- -----------
1 A 100
2 B 100
3 C 220
4 A 150
5 C 300
6 D 120
7 E 120
And this is my expectation:
Code1 Value1 Code2 Value2 Code3 Value3
----------- ----------- ----------- ----------- ----------- -----------
A 100 B 100 C 220
A 150 C 300 D 120
E 120
Should I use PIVOT to this case (and how to do this) or normal select query?
This isn't with pivot either, but in case you need to group the items into groups of 3 ordered by ID and the ID has gaps, like sometimes happen, this should do it:
select
ROW,
max(case when COL = 0 then Code end) as Code1,
max(case when COL = 0 then Value end) as Value1,
max(case when COL = 1 then Code end) as Code2,
max(case when COL = 1 then Value end) as Value2,
max(case when COL = 2 then Code end) as Code3,
max(case when COL = 2 then Value end) as Value3
FROM (
select
(row_number() over (order by ID)-1) % 3 as COL,
(row_number() over (order by ID)-1) / 3 as ROW,
Code,
Value
from
data
) X
group by ROW
This calculates row and column numbers based on row_number that increases over ID, and then uses group by to split the results into groups of 3.
SQL Fiddle
Perhaps PIVOT is not usefull here.
SELECT t1.code as code1, t1.value as value1,
t2.code as code2, t2.value as value2,
t3.code as code3, t3.value as value3
FROM tab as t1
left join tab as t2
ON t1.id = t2.id - 1
left join tab as t3
ON t2.id = t3.id - 1
where ((t1.id-1) % 3) = 0

How to uniquely number subnodes of a parent

I have a table like so
ID Node ParentID
1 A 0
2 B 1
3 C 1
4 D 2
5 E 2
6 F 3
7 G 3
8 H 3
9 I 4
10 J 4
11 K 10
12 L 11
I need a query to generate a 'position' field with the order that a node appears within its parent. Example below
ID Node ParentID Positon
1 A 0 0
2 B 1 0
3 C 1 1
4 D 2 0
5 E 2 1
6 F 3 0
7 G 3 1
8 H 3 2
9 I 4 0
10 J 4 1
11 K 10 0
12 L 11 0
select *
, row_number() over (partition by ParentID order by ID) - 1 as Position
from YourTable
As an update query:
update yt
set Position = nr
from (
select *
, row_number() over (partition by ParentID order by ID) - 1 rn
from YourTable
) yt
To update position in the original table join it to already suggested statement, either as sub-query or CTE:
;with cte (ID, Pos)
as (
select ID, row_number() over (partition by ParentID order by ID) - 1
from [Table]
)
update T
set T.Position = cte.Pos
from [Table] T
join cte on cte.ID = T.ID

Resources