Compare Current Row with Previous/Next row in SQL Server - sql

I have a table named team and it like below: I just added a row_number in the 3rd column
RaidNo OutComeID RN
2 15 1
4 15 2
6 14 3
8 16 4
10 16 5
12 14 6
14 16 7
16 15 8
18 15 9
20 16 10
22 12 11
24 16 12
26 16 13
28 16 14
30 15 15
32 14 16
34 13 17
When the OutcomeId came as 16 then start with one and 16 comes consecutively, add one by one. And the results be like
RaidNo OutComeID RN Result
2 15 1 0
4 15 2 0
6 14 3 0
8 16 4 1
10 16 5 2
12 14 6 0
14 16 7 1
16 15 8 0
18 15 9 0
20 16 10 1
22 12 11 0
24 16 12 1
26 16 13 2
28 16 14 3
30 15 15 0
32 14 16 0
34 13 17 0
Help me to get the result.

You can use the following query:
SELECT RaidNo, OutComeID, RN,
CASE
WHEN OutComeID <> 16 THEN 0
ELSE ROW_NUMBER() OVER (PARTITION BY OutComeID, grp ORDER BY RN)
END AS Result
FROM (
SELECT RaidNo, OutComeID, RN,
RN - ROW_NUMBER() OVER (PARTITION BY OutComeID ORDER BY RN) AS grp
FROM mytable) AS t
ORDER BY RN
Field grp identifies slices (also called islands) of consecutive records having the same OutComeID value. The outer query uses grp in order to enumerate each record that belongs to a '16' slice. The records that belong to the other slices are assigned value 0.
Demo here

Related

T-SQL creating a hierarchy out of orderly numbers

I have such table:
Id code
1 10
2 11
3 20
4 21
5 30
6 31
7 32
8 40
9 10
10 11
11 20
12 21
13 30
14 31
15 32
16 40
17 20
18 21
19 30
20 31
21 32
22 40
23 20
24 21
25 30
26 31
27 32
28 40
29 20
30 21
31 30
32 31
33 32
34 40
35 20
36 21
37 30
38 31
39 32
40 40
41 41
42 90
The column id represents simply the order of the records.
The column code represent the type of record.
The problem is that the records are part of a hierarchy, as shown here:
What I need to obtain is the parent of every record:
Id code Parent
1 10 1
2 11 1
3 20 1
4 21 3
5 30 3
6 31 3
7 32 3
8 40 3
9 10 9
10 11 9
11 20 9
12 21 11
13 30 11
14 31 11
15 32 11
16 40 11
17 20 9
18 21 17
19 30 17
20 31 17
21 32 17
22 40 17
23 20 9
24 21 23
25 30 23
26 31 23
27 32 23
28 40 23
29 20 9
30 21 29
31 30 29
32 31 29
33 32 29
34 40 29
35 20 9
36 21 35
37 30 35
38 31 35
39 32 35
40 40 35
41 41 40
42 90 42
The parent of every record should be expressed as its Id.
The rules are like this:
10s are their own parents since they are the roots
90s are their own parents since they are the end of data
20s parent is the previous 10
21 30 31 32 33 parent is the previous 20
40 and 50 parents is the previous 20
41 parent is the previous 40
As you can see the order in which records are is very important.
I tried to solve this declaratively (with lag() etc) and imperatively with loops but I could not find a solution.
Please help
This should work. Probably not optimal performance, but its pretty clear what its doing so should be easy to modify if (when!) your hierarchy changes.
It can obviously produce nulls if your hierarchy or ordering is not as you have prescribed
CREATE TABLE #data(id INT, code INT);
INSERT INTO #data values
(1 , 10),(2 , 11),(3 , 20),(4 , 21),(5 , 30),(6 , 31),(7 , 32),(8 , 40),(9 , 10),(10 , 11),
(11 , 20),(12 , 21),(13 , 30),(14 , 31),(15 , 32),(16 , 40),(17 , 20),(18 , 21),(19 , 30),(20 , 31),
(21 , 32),(22 , 40),(23 , 20),(24 , 21),(25 , 30),(26 , 31),(27 , 32),(28 , 40),(29 , 20),(30 , 21),
(31 , 30),(32 , 31),(33 , 32),(34 , 40),(35 , 20),(36 , 21),(37 , 30),(38 , 31),(39 , 32),(40 , 40),
(41 , 41),(42 , 90);
WITH
tens AS (SELECT id FROM #data WHERE code = 10),
twenties AS (SELECT id FROM #data WHERE code = 20),
forties AS (SELECT id FROM #data WHERE code = 40)
SELECT #data.id,
#data.code,
CASE WHEN code IN (10,90) THEN #data.id
WHEN code IN (11,20) THEN prev_ten.id
WHEN code IN (21,30,31,32,33,40,50) THEN prev_twenty.id
WHEN code = 41 THEN prev_forty.id
ELSE NULL
END AS Parent
FROM #data
OUTER APPLY (SELECT TOP (1) id FROM tens WHERE tens.id < #data.id ORDER BY tens.id DESC) AS prev_ten
OUTER APPLY (SELECT TOP (1) id FROM twenties WHERE twenties.id < #data.id ORDER BY twenties.id DESC) AS prev_twenty
OUTER APPLY (SELECT TOP (1) id FROM forties WHERE forties.id < #data.id ORDER BY forties.id DESC) AS prev_forty;
i think u should add FOREIGN KEY parentId referencing Id to existing table, fill this new column by UPDATE or gain data to fill it from external source and then u should do SELECT * FROM tableName ORDER BY parentId to receive tree structure

How to do calculate recursive sum in SQL in configurable in Big Query

I have query problem, I'm using Google BigQuery (Just to give you context if it is different). I need two value which is Value_A and Value_B. Value_A is top X value, and Value_B is the rest of top X value.Here's my Input Table
Date Value
20 10
19 10
18 10
17 10
16 10
15 10
14 10
13 10
12 10
11 10
10 10
9 10
8 10
7 10
6 10
5 10
4 10
3 10
2 10
1 10
In this case, the value of X is 6, but I need to be configurable.
In date 20, Value_A is sum from the 6 top data in Value (which is date 14 to 20), and Value_B is sum of rest of top data (which is date 14 an below).
In date 19, Value_A is sum from the 6 top data in Value (which is date 13 to 19), and Value_B is sum of rest of top data (which is date 13 an below).
Here's my output
Date Value Value_A Value_B
20 10 60 140
19 10 60 130
18 10 60 120
17 10 60 110
16 10 60 100
15 10 60 90
14 10 60 80
13 10 60 70
12 10 60 60
11 10 60 50
10 10 60 40
9 10 60 30
8 10 60 20
7 10 60 10
6 10 60 0
5 10 50 0
4 10 40 0
3 10 30 0
2 10 20 0
1 10 10 0
Below is for BigQuery Standard SQL
#standardSQL
SELECT date, value,
SUM(value) OVER(ORDER BY date DESC ROWS BETWEEN CURRENT ROW AND 5 FOLLOWING) Value_A,
IFNULL(SUM(value) OVER(ORDER BY date DESC ROWS BETWEEN 6 FOLLOWING AND UNBOUNDED FOLLOWING), 0) Value_B
FROM `project.dataset.table`
-- ORDER BY date DESC
If to apply to sample data from your question, as in below example
#standardSQL
WITH `project.dataset.table` AS (
SELECT 20 date, 10 value UNION ALL
SELECT 19, 10 UNION ALL
SELECT 18, 10 UNION ALL
SELECT 17, 10 UNION ALL
SELECT 16, 10 UNION ALL
SELECT 15, 10 UNION ALL
SELECT 14, 10 UNION ALL
SELECT 13, 10 UNION ALL
SELECT 12, 10 UNION ALL
SELECT 11, 10 UNION ALL
SELECT 10, 10 UNION ALL
SELECT 9, 10 UNION ALL
SELECT 8, 10 UNION ALL
SELECT 7, 10 UNION ALL
SELECT 6, 10 UNION ALL
SELECT 5, 10 UNION ALL
SELECT 4, 10 UNION ALL
SELECT 3, 10 UNION ALL
SELECT 2, 10 UNION ALL
SELECT 1, 10
)
SELECT date, value,
SUM(value) OVER(ORDER BY date DESC ROWS BETWEEN CURRENT ROW AND 5 FOLLOWING) Value_A,
IFNULL(SUM(value) OVER(ORDER BY date DESC ROWS BETWEEN 6 FOLLOWING AND UNBOUNDED FOLLOWING), 0) Value_B
FROM `project.dataset.table`
ORDER BY date DESC
result is
Row date value Value_A Value_B
1 20 10 60 140
2 19 10 60 130
3 18 10 60 120
4 17 10 60 110
5 16 10 60 100
6 15 10 60 90
7 14 10 60 80
8 13 10 60 70
9 12 10 60 60
10 11 10 60 50
11 10 10 60 40
12 9 10 60 30
13 8 10 60 20
14 7 10 60 10
15 6 10 60 0
16 5 10 50 0
17 4 10 40 0
18 3 10 30 0
19 2 10 20 0
20 1 10 10 0

Return running max column from another column SQL

I have a query where I would like to manipulate a column to return an array conatining only the max-value from the last 12 values from another column (due to other parts of the query).
Example:
I want to add the column MaxLast12 from:
Month Power
1 10
2 16
3 8
4 14
5 15
6 3
7 6
8 10
9 11
10 12
11 12
12 12
13 18
14 12
To become:
Month Power MaxLast12
1 10 10
2 16 16
3 8 16
4 14 16
5 15 16
6 3 16
7 6 16
8 17 17
9 11 17
10 12 17
11 12 17
12 12 17
13 18 18
14 12 18
It would also help to be able to create a simpler solution where I only include the 12 rows in the query (won't be as accurate but good enough for the purpose) with only the maximum value. Would need to do the following:
Month Power
1 6
2 6
3 8
4 14
5 15
6 3
7 6
8 10
9 11
10 12
11 12
12 12
To become:
Month Power YearMax
1 10 17
2 16 17
3 8 17
4 14 17
5 15 17
6 3 17
7 6 17
8 17 17
9 11 17
10 12 17
11 12 17
12 12 17
Since I'm guessing both problems solution will be similar, any help possible is appriciated. Would like to avoid usign GROUP BY clause since I'm modifying an existing kind of complex query.
Tried to achive this using max() with no luck.
I am using SQL-developer.
In Oracle you would use window functions:
select month, power,
max(power) over (order by month rows between 11 preceding and current row)
from t;

Select sum of condition

I have a table like below. I want to select some rows that sum of cnt<120. how to do this?
cnt id
_________
6 14001
17 14005
14 14017
16 14024
9 14025
7 14027
10 14029
14 14048
23 14055
18 14056
19 14058
18 14059
18 14063
15 14064
9 14086
17 14095
9 14098
14 14116
10 14138
8 14147
17 14165
22 14171
22 14191
18 14194
13 14204
17 14221
13 14245
14 14249
6 14254
17 14257
9 14260
19 14261
26 14263
6 14264
27 14265
19 14269
11 14287
SELECT SUM(cnt)
FROM my_table
WHERE cnt < 120
You can try this:-
SELECT *
FROM test O
HAVING (SELECT sum(cnt) FROM test WHERE cnt <= O.cnt) <120

select last entry for every user multi table example

Given the following tables
table message
id message time_send
14 "first" 2014-02-10 22:16:31
15 "second" 2014-02-14 09:35:20
16 "third" 2014-02-13 09:35:47
17 "fourth" 2014-03-10 22:16:31
18 "fifth" 2014-03-14 09:35:20
19 "sixth" 2014-04-12 09:35:47
20 "seventh" 2014-04-13 09:35:47
21 "eighth" 2014-04-14 09:35:47
table message_owner
id message_id owner_id cp_id
1 14 1 4
2 14 4 1
3 15 12 4
4 15 4 12
5 16 4 1
6 16 1 4
7 17 12 4
8 17 4 12
9 18 4 1
10 18 1 4
11 19 12 4
12 19 4 12
13 20 12 1
14 20 1 12
15 21 12 7
16 21 7 12
I want to query the most recent message with every counter party(cp_id) for a given owner.
For example for owner_id=4 I would like the following output:
id message time_send owner_id cp_id
18 "fifth" 2014-03-14 09:35:20 4 1
19 "sixth" 2014-02-13 09:35:47 4 12
I see a lot of examples with one table but I am not able to transpose them in a multitable example.
edit1: adding more entries
This should work:
SELECT m.id, m.message, mo.owner_id, mo.cp_id
FROM message m
JOIN message_owner mo ON m.id=mo.message_id
WHERE mo.owner_id=4
AND m.time_send=(
SELECT MAX(time_send)
FROM message m2
JOIN message_owner mo2 ON mo2.message_id=m2.id
WHERE mo2.owner_id=mo.owner_id
AND mo2.cp_id =mo.cp_id
)
... notice though that putting a WHERE condition on a timestamp column can sometimes not work correctly.
Same example without jointures:
SELECT m.id, m.time_send, m.message, mo.owner_id, mo.cp_id
FROM message m, message_owner mo
WHERE m.id = mo.message_id
AND mo.owner_id = 4
AND m.time_send = (
SELECT MAX(time_send)
FROM message m2, message_owner mo2
WHERE mo2.message_id = m2.id
AND mo2.owner_id = mo.owner_id
AND mo2.cp_id = mo.cp_id
);
http://sqlfiddle.com/#!2/558d7/4