How to construct SQL query for this...? - sql

I would like to do some math operation but for each row at the time.
For example:
A B C D
-------------------------------
100 -50 =50 20160101
100 0 =150 20160102
100 -50 =100 20160103
So basically column C would always be sum of all past A +(B) columns, but not future ones. Does anyone have idea on how to achieve this in SQL?
I can do this in code, but I would like to do this in SQL and just show result in table.
P.S. my english is not the best, so feel free to ask if I was not clear enough.

This is called a cumulative or running sum. The normal method uses ANSI standard window functions:
select a, b,
sum(a + b) over (order by d) as c,
d
from t;
If your version of SQL doesn't support window functions, then you can use a correlated subquery (performance would generally be much worse):
select a, b,
(select sum(a + b) from t t2 where t2.d <= t.d) as c,
d
from t;

Related

For each value in col A finding number of values in column B that are greater than it

Let's say I have a table with 2 columns - A & B.
Using plain SQL (No scripts/cursors etc.), how do I (window function?) calculate for EACH value in column A the number of values in column B that are bigger/smaller than it?
Thanks you.
You would use conditional aggregation:
select a,
sum(case when b < a then 1 else 0 end)
from t
group by a;
Window functions don't seem appropriate to this question.

Identifying the most purchased combination of items in SQL

First of all, I hope everyone's staying safe out there.
So here's my question.
Currently I'm trying to figure out how I can identify the most purchased combination of items.
Most purchased combination of items must appear at the top (descending order is crucial).
Let's say I have a sales table that looks like this:
Cust_ID Item_ID
100 A
100 A
100 B
100 C
200 A
200 C
200 C
300 B
400 A
400 B
and the expected output looks something like this:
Comb_of_Item Count_of_Cust
A, B 10
A, C 7
B, C 4
A, B, C 2
Note that Customer 100 had purchased item "A" twice, which for the purpose of this exercise will be ignored (dups to be removed).
This means that Customer 100 would be counted as "A, B, C" NOT "A, A, B, C"
Any help/suggestion would be much appreciated.
Many thanks advance!
I believe this can be modify into a better query but right now this will get the job done.
select combo_of_item,count(combo_of_item) Count_of_Cust from (
select Cust_ID ,string_agg(Item_ID,',') combo_of_item from (
select distinct * from [table] ) a
group by Cust_ID) b
group by Combo_of_item
db<>fiddle
btw since OP didn't provide dbms, string_egg might have to alter depends on which db OP is currently using.

Calculating values from two tables where one has key in header and one has it in column values

I have a simple problem that I dont know how to solve in sql.
I have two tables,
cost :
a | b | c
-------+-------+---------------
31.99 | 14.12 | 133.1
second table: income
Party | sum
------+--------
A | 90
B | 12
C | 70
Now i want to get a result that substract for each party A, B, C the income-cost and finds the net value. I cannot compare the column header to column value. I am quite new to this, so I am struggling quite a lot. There should be really easy way of doing this.
I created the 'cost' table by
SELECT sum(A) as A, sum(B) as B, sum(C) as C FROM mytable;
may be there is clever way of creating this table in the same formate as income table that would make it easier to compare? I will appreciate any suggeestion on any of the two fronts. Thanks a lot!
You can compare, using case:
select party,
cost - (case when party = 'a' then a
when party = 'b' then b
when party = 'c' then c
else 0 end)
from cost c cross join
income i

Is my query correct? Can I optimize it? Positive sum and negative sum of integers

I have two solutions for finding the sum of positive integers and negative integers. Please,tell which one is more correct and more optimized?
Or Is there any other more optimized and correct query ?
Q:
Consider Table A with col1 and below values.
col1
20
-20
40
-40
-30
30
I need below output
POSITIVE_SUM NEGATIVE_SUM
90 -90
I have two solutions.
/q1/
select POSITIVE_SUM,NEGATIVE_SUM from
(select distinct sum(a2.col1) AS "POSITIVE_SUM" from A a1 join A a2 on a2.col1>0
group by a1.col1)
t1
,
(select distinct sum(a2.col1) AS "NEGATIVE_SUM"from A a1 join A a2 on a2.col1<0
group by a1.col1) t2;
/q2/
select sum (case when a1.col1 >= 0 then a1.col1 else 0 end) as positive_sum,
sum (case when a1.col1 < 0 then a1.col1 else 0 end) as negative_sum
from A a1;
POSITIVE_SUM NEGATIVE_SUM
90 -90
I wonder how you even came up with your 1st solution:
- self-join (twice) the table,
- producing 6 (identical) rows each and finally with distinct get 1 row,
- then cross join the 2 results.
I prepared a demo so you can see the steps that lead to the result of your 1st solution.
I don't know if this can be in any way optimized,
but is there case that it can beat a single scan of the table with conditional aggregation like your 2nd solution?
I don't think so.
The second query is not only better performing, but it returns the correct values. If you run the first query, you'll see that it returns multiple rows.
I think for the first query, you are looking for something like:
select p.positive_sum, n.negative_sum
from (select sum(col1) as positive_sum from a1 where col1 > 0) p cross join
(select sum(col1) as negative_sum from a1 where col1 < 0) n
And that you are asking wither the case expression is faster than the where.
What you are missing is that this version needs to scan the table twice. Reading data is generally more expensive than any functions on data elements.
Sometimes the second query might have very similar performance. I can think of three cases. First is when there is a clustered index on col1. Second is when col1 is used as a partitioning key. And third is on very small amounts of data (say data that fits on a single data page).

Search for the occurrence of a list of values

I'm trying to find an optimized way to identify if a specific set of values exists in a list.
For example, lets assume the following list of records in a table
Id Value
1 A
2 B
3 A
4 C
5 A
6 B
7 C
8 C
9 A
I'm trying to find a way to check how much times the sequence {A, B} or {A, B, C} occurs, for example.
I know I can do this with cursors but I was checking if there's any other option that would be preferable in terms of performance.
The result I'd expect would by something like this:
{A, B}: 2 times:
{A, B, C}: 1 time.
I'm using Sql Server.
Probably the simplest way is to use the ANSI standard functions lag() and/or lead():
select count(*)
from (select t.*,
lead(value) over (order by id) as next_value,
lead(value, 2) over (order by id) as next_value2,
from t
) t
where value = 'A' and next_value = 'B' and next_value2 = 'C';