I want to add a column to my select showing a set of number from say 1 to 4.
Example:
Select * gives me
Id Transaction
1 10
2 11
3 12
4 13
5 14
6 15
I want to add a column called "Flow". The result should be like this.
Id Transaction Flow
1 10 1
2 11 2
3 12 3
4 13 4
5 14 1
6 15 2
In this example the flow is from 1-4. Could be 1-n.
No particular relation between Id and Flow is needed.
If you're using SQL Server or other DBMS that allows ROW_NUMBER, you could do this:
CREATE TABLE #Tbl(Id INT, [Transaction] INT);
INSERT INTO #Tbl VALUES
(1, 10), (2, 11), (3, 12), (4, 13), (5, 14), (6, 15);
DECLARE #N INT = 4;
SELECT *,
Flow = 1 + ((ROW_NUMBER() OVER(ORDER BY Id) - 1) % #N)
FROM #Tbl
DROP TABLE #Tbl;
If you are using mySql.
Query
set #r := 0;
select Id, `Transaction`,
#r := (#r % 4) + 1 as Flow
from your_table_name
order by Id;
Demo
EDIT
Following sql query can be used irrespective of rdbms.
Query
select *, (
select ((count(*) - 1) % 4) + 1 as Flow
from your_table_name t2
where t1.Id >= t2.Id
) as Flow
from your_table_name t1;
Related
Assume I have the following data:
ID
T_Min
T_Max
1
3
5
2
1
4
I would like to create the following table using SQL (Snowflake):
ID
T
1
3
1
4
1
5
2
1
2
2
2
3
2
4
Does someone know how to do this? Thank you very much in advance!
Sample data:
CREATE OR REPLACE TABLE T1 (
ID INT,
T_Min INT,
T_Max INT);
INSERT INTO T1(ID, T_Min, T_Max)
SELECT * FROM VALUES (1, 3, 5), (2, 1, 4) t(ID, T_Min, T_Max);
Solution:
WITH N AS (
SELECT ROW_NUMBER() OVER(ORDER BY SEQ4()) AS T FROM TABLE(GENERATOR(ROWCOUNT => 1000)) -- Set to the maximum value of the difference between T_Max and T_Min
)
SELECT T1.ID, N.T
FROM T1
JOIN N ON N.T BETWEEN T1.T_Min AND T1.T_Max
ORDER BY T1.ID, N.T;
I need to create partitions. Suppose I have this table:
CREATE TABLE MyTable (Pos INT UNIQUE, X INT)
INSERT INTO MyTable VALUES (3, 2)
INSERT INTO MyTable VALUES (5, 0)
INSERT INTO MyTable VALUES (6, 0)
INSERT INTO MyTable VALUES (9, 0)
INSERT INTO MyTable VALUES (43, 9)
INSERT INTO MyTable VALUES (53, 8)
INSERT INTO MyTable VALUES (56, 0)
INSERT INTO MyTable VALUES (81, 0)
INSERT INTO MyTable VALUES (163, 1)
INSERT INTO MyTable VALUES (9716, 0)
The query result should be this table with a column Y added, Y should be
IF X=0 : the previous value X<>0 (OR NULL, if not exists), ordered by Pos
IF X<>0 : X
Desired answer table looks like this
SELECT *
FROM MyQuery as a function of MyTable
ORDER BY Pos
Pos X Y
3 2 2
5 0 2
6 0 2
9 0 2
43 9 9
53 8 8
56 0 8
81 0 8
163 1 1
9716 0 1
This is a type of gaps-and-islands problem.
There are many solutions, here is one:
Use a running conditional count to number the rows that we want to group together
Use a partitioned conditional MIN to take the only value that we actually want, per group
WITH StartPoints AS (
SELECT *,
GroupId = COUNT(NULLIF(X, 0)) OVER (ORDER BY Pos)
FROM MyTable
)
SELECT
Pos,
X,
Y = MIN(NULLIF(X, 0)) OVER (PARTITION BY GroupId)
FROM StartPoints
ORDER BY Pos;
db<>fiddle
I don't know what would be the appropriate title for this problem, but here is what I need to accomplish
Here is my dataset:
State TimeInState
--------------------------
1 20
3 0
4 5
8 2
5 10
1 18
3 30
12 2
2 0
What I want is another column in here, lets say FooID. What FooID is a int value that will remain same until the state is 1 again.
So the dataset would look like this:
State TimeInState FooID
------------------------------------------
1 20 1
3 0 1
4 5 1
8 2 1
5 10 1
1 18 2
3 30 2
12 2 2
2 0 2
So if there was another row at the end with State=1 then FooID will be 3 until the next state is changed.
How can I accomplish this in T-SQL?
Thanks in advance.
If you have some way of ordering rows (like an ID of sorts), then here is an example of how you could do something like this:
DECLARE #T TABLE (ID INT IDENTITY(1, 1), State INT, TimeInState INT)
INSERT #T (State, TimeInState)
VALUES (1, 20), (3, 0), (4, 5), (8, 2), (5, 10), (1, 18)
, (3, 30), (12, 2), (2, 0), (1, 1), (1, 1), (2, 1);
WITH CTE AS (
SELECT *
, ROW_NUMBER() OVER (ORDER BY CASE WHEN State = 1 THEN 0 ELSE 1 END, ID) RN
FROM #T
)
SELECT State, TimeInState, Foo.FooID
FROM CTE T
CROSS APPLY (SELECT MAX(RN) FooID FROM CTE WHERE State = 1 AND ID <= T.ID) Foo
ORDER BY ID;
But if you don't have the data ordered in some way already, then I don't think you can ensure the result set will sort the data in the way you want to sort it.
I have a simple question but its kinda difficult for me to solve it.
I would like to have sum up a specific column till it reached a limit and resets it self. (SQL 2012)
Lets say the limit is 50
- List item
- Value Total
- 10 10
- 20 30
- 30 60
- 40 50 (60-limit) + the current row value
- 2 2
- 3 5
- 10 15
- 25 40
- 15 55
- 5 10 (55-limit) + the current row value
Thank you very much.
This should do it if you have SQL Server 2012 or later:
DECLARE #Table TABLE (Id INT, ListItem INT);
INSERT INTO #Table VALUES (1, 10);
INSERT INTO #Table VALUES (2, 20);
INSERT INTO #Table VALUES (3, 30);
INSERT INTO #Table VALUES (4, 40);
INSERT INTO #Table VALUES (5, 2);
INSERT INTO #Table VALUES (6, 3);
INSERT INTO #Table VALUES (7, 10);
INSERT INTO #Table VALUES (8, 25);
INSERT INTO #Table VALUES (9, 15);
INSERT INTO #Table VALUES (10, 5);
WITH RunningTotal AS (
SELECT Id, ListItem, SUM(ListItem) OVER (ORDER BY Id) % 50 AS RT FROM #Table)
SELECT
rt.Id,
rt.ListItem,
CASE WHEN rt.RT < rt2.RT THEN rt.RT + 50 ELSE rt.RT END AS RunningTotal
FROM
RunningTotal rt
LEFT JOIN RunningTotal rt2 ON rt2.Id = rt.Id - 1
ORDER BY
rt.Id;
The tricky bit is allowing the numbers to overflow the 50 one time, otherwise this would be trivial.
Results are:
Id LI RunningTotal
1 10 10
2 20 30
3 30 60
4 40 50
5 2 2
6 3 5
7 10 15
8 25 40
9 15 55
10 5 10
create table running_totals
(
id int identity(1,1),
val int
)
insert into running_totals
select 1 union all
select 20 union all
select 10 union all
select 30 union all
select 50 union all
select 10 union all
select 11 union all
select 22 union all
select 40 union all
select 60 union all
select 20 union all
select 10 union all
select 15
declare cur_run_tot cursor for select id,val from running_totals order by id asc
declare #id int ,#val int,#runtot int
open cur_run_tot
create table #RunTot
(
id int,val int, runtot int
)
fetch next from cur_run_tot into #id,#val
while ##FETCH_STATUS = 0
begin
if #runtot is null or #runtot+#val > 50
set #runtot = #val
else
set #runtot = #runtot+ #val
insert into #RunTot
select #id,#val,#runtot
fetch next from cur_run_tot into #id,#val
end
select id as ID, val as Current_Value, runtot as Running_Total from #RunTot
drop table #RunTot
deallocate cur_run_tot
I have a where statement that depends on an id and based off the id the next where is determined. EX: if ID = 1 the where statement should be a<= 3 and b between 4 and 7 if ID <> 1 the where statement should be a<= 4 and b between 5 and 7. Not sure how to do this. Tried a Case clause but had no luck.
Here is a sample table in tempdb with data.
-- Just a test
use tempdb;
go
-- Drop table
if object_id('test') > 0
drop table test
go
-- Create table
create table test
(
id int,
a int,
b int
);
-- Add data
insert into test values
(1, 3, 4),
(2, 4, 5),
(1, 4, 4),
(2, 5, 5),
(1, 3, 3),
(2, 4, 4);
-- Full table
select * from test;
Here is a solution using the CASE statement.
-- Show the data
select
*
from
test
where
(
case
when id = 1 and a <= 3 and b between 4 and 7 then 1
when id <> 1 and a <= 4 and b between 5 and 7 then 1
else 0
end
) = 1;
Something like:
where
(id = 1 and a <= 3 and b between 4 and 7) or
(id <> 1 and a <= 4 and b between 5 and 7)
Based on your requirements you just need to parenthetical WHERE statements with an OR:
...
WHERE (ID = 1 AND a <= 3 AND b BETWEEN 4 AND 7)
OR (ID <> 1 AND a<= 4 AND b BETWEEN 5 AND 7)