I want to get data from 2 tables ordering them by date: to get the cumulative balance for the customer.
The 2 tables that I want to get data from are my tables: transfers & trans_payments I had done this using an SQL server and here is the query:
SELECT TOP 1000000
ROW_NUMBER() OVER (ORDER BY (SELECT 1)) num_col,
ID, cust_id, final, value, date,
SUM(balance) OVER (PARTITION BY cust_id
ORDER BY date, seq, ID) balance,
note
FROM
(SELECT
ID, cust_id, final, 0, final balance, date, note, 0
FROM
transfers
UNION ALL
SELECT
ID, cust_id, 0, value, - value, date, note, 1
FROM
trans_payments) t (ID, cust_id, final, value, balance, date, note, seq)
ORDER BY
cust_id, date, seq
But I want to convert this query to use it in SQLite and here what I did until now :
SELECT ROW_NUMBER() OVER (ORDER BY
(SELECT 1)) num_col, ID, cust_id, final, value, date, sum(balance) OVER
(partition BY cust_id
ORDER BY date, seq, ID) balance, note
FROM (SELECT ID, cust_id, final, 0, final balance, date, note, 0
FROM transfers UNION ALL
SELECT ID, cust_id, 0, value, - value, date, note, 1
FROM trans_payments) t (ID, cust_id, final, value, balance, date, note, seq)
ORDER BY cust_id, date, seq
but I'm getting this error:near "near "(": syntax error
transfers:
ID int
cust_id int
tfrom nvarchar(200)
tto nvarchar(200)
price decimal(18, 2)
tax decimal(18, 2)
final Calculated
tnumber nvarchar(30)
note nvarchar(MAX)
date date
trans_payments:
ID int
cust_id int
value decimal(18, 2)
method nvarchar(30)
note nvarchar(MAX)
date date
Let's assume I have this data:
transfers:
ID cust_id final date
1 5 3000 22-09-2020
2 5 1500 25-09-2020
3 10 4000 28-09-2020
trans_payments:
ID cust_id value date
1 5 1000 22-09-2020
2 5 1500 23-09-2020
3 5 1000 01-10-2020
4 10 1000 28-09-2020
5 10 2000 01-10-2020
I want to create a view to show customers action on Purchases and Payments like this:
Customer 5:
cust_id final value Balance date
5 3000 0 3000 22-09-2020 --- > Purchases
5 0 1000 2000 22-09-2020 --- > payment
5 0 1500 500 23-09-2020 --- > payment
5 1500 0 2000 25-09-2020 --- > P
5 0 1000 1000 23-09-2020 --- > payment purchases
Here
In SQLite you should set the column aliases of a subquery inside the subquery.
Also, use LIMIT after the ORDER BY clause instead of TOP:
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) num_col,
ID, cust_id, final, value, date,
SUM(balance) OVER (PARTITION BY cust_id ORDER BY date, seq, ID) balance,
note
FROM (
SELECT ID, cust_id, final, 0 value, final balance, date, note, 0 seq
FROM transfers
UNION ALL
SELECT ID, cust_id, 0, value, - value, date, note, 1
FROM trans_payments
)
ORDER BY cust_id, date, seq
LIMIT 1000000
See the demo.
Related
I having table like below in Sql Server. I need to get data within in a date range, for example -: StartDate = '2020-09-01' and EndDate = '2020-09-11'. Its quite simple to get data between a date range but complicated part is that,i need to Sum up data in every 2nd day in the selected date range.
For Example -:
As in the above image, i need to Sum up of SKU in every 2nd day in single column. Could anyone help me out with the query for this result output.
CREATE TABLE #Temp
(
Sku Nvarchar(50),
OrderDate DateTime,
Quantity Int,
)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-01 00:00:00.000',2)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-02 00:00:00.000',1)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-03 00:00:00.000',3)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-04 00:00:00.000',4)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-05 00:00:00.000',5)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-06 00:00:00.000',6)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-07 00:00:00.000',2)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-08 00:00:00.000',1)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-09 00:00:00.000',3)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-10 00:00:00.000',1)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#xyz','2020-09-11 00:00:00.000',10)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#abc','2020-09-01 00:00:00.000',1)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#abc','2020-09-02 00:00:00.000',10)
INSERT INTO #Temp(Sku,OrderDate,Quantity)Values('#abc','2020-09-03 00:00:00.000',10)
select * from #Temp
Use row_number() window function to generate a sequence number per Sku. Do a GROUP BY (rn - 1) / 2. HAVING COUNT(*) = 2 is to only consider those with 2 rows
; with
cte as
(
select *, rn = row_number() over (partition by Sku order by OrderDate)
from #Temp
)
select Sku, sum(Quantity)
from cte
group by Sku, (rn - 1) / 2
having count(*) = 2
order by Sku , (rn - 1) / 2
Use STRING_AGG if you want the result in CSV.
With ROW_NUMBER() and LAG() window functions:
select Sku, Quantity
from (
select Sku,
row_number() over (partition by Sku order by OrderDate) rn,
Quantity + lag(Quantity) over (partition by Sku order by OrderDate) Quantity
from #Temp
where OrderDate between '20200901' and '20200911'
) t
where rn % 2 = 0
order by Sku, rn;
See the demo.
Results:
> Sku | Quantity
> :--- | -------:
> #abc | 11
> #xyz | 3
> #xyz | 7
> #xyz | 11
> #xyz | 3
> #xyz | 4
Something like this
;with
string_cte(Sku, OrderDate, Quantity, rn_grp) as(
select *, (row_number() over (partition by Sku order by OrderDate)+1)/2
from #Temp),
sum_cte(Sku, rn_grp, sum_quantity) as (
select Sku, rn_grp, sum(quantity)
from string_cte
group by Sku, rn_grp
having count(*)>1)
select
Sku, string_agg(sum_quantity, ',') within group (order by rn_grp) SecondDaySumUp
from sum_cte
group by Sku
order by 1 desc;
Output
Sku SecondDaySumUp
#xyz 3,7,11,3,4
#abc 11
I want to get the MIN and MAX from a certain values and put them in columns beside each other. Here's my query but I don't know how to transpose the values...
SELECT *
, MIN([CID]) OVER (PARTITION BY [TID] ORDER BY [TID]) MinID
, MAX([CID]) OVER (PARTITION BY [TID] ORDER BY [TID]) MaxID
Given:
TID CID DATE
123456789 1 01JAN
123456789 2 02JAN
123456789 3 03JAN
123456789 4 04JAN
Result:
TID CID DATE MIN MAX DATEMIN DATEMAX
123456789 1 01JAN 1 4 01JAN 04JAN
Isn't simple aggregation good enough here?
select
tid,
min(cid) min_cid,
max(cid) max_cid,
min(date) min_date,
max(date) max_date
from mytable
group by tid
Or, if the cids and dates are not changing accordingly, you can use conditional aggregation:
select
tid,
max(case when rn_asc = 1 then cid end) cid_at_min_date,
max(case when rn_desc = 1 then cid end) cid_at_max_date,
min(date) min_date,
max(date) max_date
from (
select
t.*,
row_number() over(partition by tid order by cdate asc ) rn_asc,
row_number() over(partition by tid order by cdate desc) rn_desc
from mytable t
) t
where 1 in (rn_asc, rn_desc)
group by tid
This orders records by cdate, and gives you the cids that correspond to the minimum and maximum date. You can easily adapt the query if you want things the other way around (basically, switch cid and cdate).
I have my data which may be around 50 records for each address:
Id AddressId Income Expense Revenue
----------------------------------------
1 1 100 200 300
2 1 150 20 200
3 1 160 80 800
4 1 50 90 200
5 1 600 700 500
Now I need my data in the following format:
Ids Count Income Expense Revenue
---------------------------------------
1 1 100 200 300
1,2 2 250 220 500
1,2,3 3 410 300 1300
1,2,3,4 4 460 390 1500
1,2,3,4,5 5 1060 1090 2000
Every row is being added one after another.
For example:
The Ids 1,2 is a sum of Id 1 and 2
The Ids 1,2,3 is a sum of Id 1 and 2 and 3 and so on
I don't need the Ids column, the only thing I need is the sum
You could use STUFF, ROW_NUMBER() OVER(), and SUM() OVER() like this
DECLARE #SampleData AS TABLE
(
Id int,
AddressId int,
Income int,
Expense int,
Revenue int
)
INSERT INTO #SampleData
VALUES
( 1, 1, 100, 200, 300),
( 2, 1, 150, 20 , 200),
( 3, 1, 160, 80 , 800),
( 4, 1, 50 , 90 , 200),
( 5, 1, 600, 700, 500)
SELECT
STUFF(
(
SELECT ',' + CAST(sd1.Id AS varchar(10))
FROM #SampleData sd1
WHERE sd1.AddressId = sd.AddressId AND sd1.Id <= sd.Id
FOR XML PATH('')
),
1,1,'') AS Ids,
Row_number() OVER(PARTITION BY sd.AddressId ORDER BY sd.Id) AS Count,
sum(sd.Income) OVER(PARTITION BY sd.AddressId ORDER BY sd.Id) AS Income,
sum(sd.Expense) OVER(PARTITION BY sd.AddressId ORDER BY sd.Id) AS Expense,
sum(sd.Revenue) OVER(PARTITION BY sd.AddressId ORDER BY sd.Id) AS Revenue
FROM #SampleData sd
ORDER BY sd.AddressId, sd.Id
Demo link: http://rextester.com/HRIWH92029
Note: The last revenue should be 2000 instead of 1600
If you're using SQL server 2012 and above,
please use below query for the sum up the previous rows
Select ID,
count(*) OVER (PARTITION by AddressID
ORDER BY ID
ROWS BETWEEN unbounded PRECEDING AND current row) as[Count],
sum(Income) OVER (PARTITION by AddressID
ORDER BY ID
ROWS BETWEEN unbounded PRECEDING AND current row) Income,
sum(Expense) OVER (PARTITION by AddressID
ORDER BY ID
ROWS BETWEEN unbounded PRECEDING AND current row)Expense,
sum(Revenue) OVER (PARTITION by AddressID
ORDER BY ID
ROWS BETWEEN unbounded PRECEDING AND current row) Revenue from TableName
If you're using SQL server 2008 and below, please use below query for the sum up the previous rows.
Select ID, (select count(*) from Tablename A where A.Id<=Tablename.ID)[Count],
(select sum(Income) from Tablename A where A.Id<=Tablename.ID) Income, (select
sum(Expense) from Tablename A where A.Id<=Tablename.ID) Expense, (select
sum(Revenue) from Tablename A where A.Id<=Tablename.ID) Revenue from Tablename
I want to select last record of price column of my table where my value of column is greater than zero. How can I do that?
My stored procedure is :
SELECT
id, name, price
FROM
messages
WHERE
id IN (SELECT MAX(id)
FROM messages
WHERE price > 0
GROUP BY name)
The problem is that this code select max id that price is greater than zero not last id. Means select id=2 and id=6
But in last id of group (frank) price is zero but this stored procedure select id=2 while I want stored procedure select only id =6
id name price
--------------
1 frank 1000
2 frank 500
3 frank 0
4 john 200
5 john 100
6 john 20
There are multiple ways to approach this. Following your method, though, you just need to move the price comparison to the outer query:
SELECT id, name, price
FROM messages
WHERE price > 0 AND
id IN (SELECT MAX(id)
FROM messages
GROUP BY name
);
I would be more inclined to write this as:
select m.*
from (select m.*,
row_number() over (partition by name order by id desc) as seqnum
from messages m
) m
where seqnum = 1 and price > 0;
with cte as (
select row_number() over(partition by id order by id desc) rn,
id,name,price
from messages
)
select id,name,price
from cte
where rn=1 and price>0
Something like this.
This is an Employee table,
Id Name Salary
1 A.J 7000
2 B.S 30000
3 C.K 2000
4 D.O 10000
5 E.L 500
Now i want to display 1st highest salary then minimum salary then 2nd maximum salary then 2nd minimum salaray and so on..up to nth row.
Expected Output,
Id Name Salary
2 B.S 30000
5 E.L 500
4 D.O 10000
3 C.K 2000
1 A.J 7000
One more variant without explicit COUNT. SQL Fiddle.
Try also to add this row to sample data (6, 'X.Y', 7000) in the fiddle. The query still returns correct results.
DECLARE #Employee TABLE (ID int, Name nvarchar(50), Salary money);
INSERT INTO #Employee (ID, Name, Salary) VALUES
(1, 'A.J', 7000),
(2, 'B.S', 30000),
(3, 'C.K', 2000),
(4, 'D.O', 10000),
(5, 'E.L', 500);
WITH
CTE
AS
(
SELECT *, NTILE(2) OVER (ORDER BY Salary, ID) AS n
FROM #Employee AS E
)
SELECT
*
,SIGN(n-1.5) AS s
,SIGN(n-1.5)*Salary AS ss
,ROW_NUMBER() OVER(PARTITION BY n ORDER BY SIGN(n-1.5)*Salary DESC) AS rn
FROM CTE
ORDER BY rn, ss DESC;
Result
ID Name Salary n s ss rn
2 B.S 30000.00 2 1.0 30000.00000 1
5 E.L 500.00 1 -1.0 -500.00000 1
4 D.O 10000.00 2 1.0 10000.00000 2
3 C.K 2000.00 1 -1.0 -2000.00000 2
1 A.J 7000.00 1 -1.0 -7000.00000 3
I left intermediary columns in the output to illustrate how it works.
Using Row_Number() and Count()
Fiddle Demo
declare #count int=(select count(1) from Employee);
with cte1 as
(
select ROW_NUMBER() over(order by salary desc) as rn,0 Sort,Id,Name,Salary, count(Id) over () cnt from Employee
union all
select ROW_NUMBER() over(order by salary) as rn,1 Sort,Id,Name,Salary, count(Id) over () cnt from Employee
)
select top (#count) Id,Name,Salary from cte1 where rn <= (floor(cnt/2) + cnt%2) order by rn,sort
Below is the solution:
--Create dummy employee table
CREATE TABLE tbl_Employee
(
Id INT,
Name VARCHAR(100),
Salary NUMERIC(9, 2)
)
GO
--Insert few dummy rows in the table
INSERT INTO #Employee
(Id, Name, Salary)
VALUES(100, 'John', 7000),
(101, 'Scott', 30000),
(102, 'Jeff', 2000),
(103, 'Jimy', 10000),
(104, 'Andrew', 500),
(105, 'Alister', 100)
GO
--Get data as required
DECLARE #Cnt INT = 0, #SeqLimit INT = 0
SELECT #Cnt = COUNT(1) FROM tbl_employee
SET #SeqLimit = CEILING(#Cnt / 2.0)
SELECT * FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY Salary DESC) AS SEQ, Id, Name, Salary FROM tbl_employee
)DT1
WHERE SEQ <= #SeqLimit
UNION ALL
SELECT * FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY Salary ASC) AS SEQ, Id, Name, Salary FROM tbl_employee
)DT2
WHERE SEQ <= #SeqLimit - (#Cnt % 2)
ORDER BY SEQ ASC, Salary DESC
The same can be achieved with different approaches and here you can find more on this:
http://www.sqlrelease.com/order-max-and-min-value-rows-alternatively-in-sql-server