How can I use SUM() OVER() - sql

I can't understand this code's bug
ID AccountID Quantity
1 1 10 Sum = 10
2 1 5 = 10 + 5 = 15
3 1 2 = 10 + 5 + 2 = 17
4 2 7 = 7
5 2 3 = 7 + 3 = 10
SELECT ID, AccountID, Quantity,
SUM(Quantity) OVER (PARTITION BY AccountID ) AS TopBorcT,
FROM tCariH

Seems like you expected the query to return running totals, but it must have given you the same values for both partitions of AccountID.
To obtain running totals with SUM() OVER (), you need to add an ORDER BY sub-clause after PARTITION BY …, like this:
SUM(Quantity) OVER (PARTITION BY AccountID ORDER BY ID)
But remember, not all database systems support ORDER BY in the OVER clause of a window aggregate function. (For instance, SQL Server didn't support it until the latest version, SQL Server 2012.)

if you are using SQL 2012 you should try
SELECT ID,
AccountID,
Quantity,
SUM(Quantity) OVER (PARTITION BY AccountID ORDER BY AccountID rows between unbounded preceding and current row ) AS TopBorcT,
FROM tCariH
if available, better order by date column.

Query would be like this:
SELECT ID, AccountID, Quantity,
SUM(Quantity) OVER (PARTITION BY AccountID ) AS TopBorcT
FROM #Empl ORDER BY AccountID
Partition by works like group by. Here we are grouping by AccountID so sum would be corresponding to AccountID.
First first case, AccountID = 1 , then sum(quantity) = 10 + 5 + 2 =>
17 & For AccountID = 2, then sum(Quantity) = 7+3 => 10
so result would appear like attached snapshot.

Related

How to calculate average omitting duplicates per partition in SQL?

I want to calculate the average item count accounting for sub-partitions in each partition.
Sample Data:
id session item_count random_field_1
1 weoifn2 3 A
1 weoifn2 3 B
1 iuboiwe 2 K
2 oeino33 5 R
2 vergeeg 8 C
2 feooinn 9 P
2 feooinn 9 M
Logic:
id = 1: (3 + 2) / 2 = 2.5
id = 2: (5 + 8 + 9) / 3 = 7.33
Expected Output:
id avg
1 2.5
2 7.33
My Query:
SELECT
id
, AVG(item_count) OVER (PARTITION BY id) AS avg
FROM my_table
However, I believe this will factor in duplicates twice, which is unintended. How can I fix my query to only consider one item_count value per session?
Consider below approach
select id, avg(item_count) as avg
from (
select distinct id, session, item_count
from your_table
)
group by id
if applied to sample data in your question - output is
SELECT id, AVG(item_count) OVER (PARTITION BY id) AS avg
FROM (
SELECT
id
, CASE
WHEN ROW_NUMBER OVER (PARTITION BY id) = 1
THEN item_count
ELSE NULL
END
AS item_count
FROM my_table
)

Find gaps of a sequence in PostgreSQL tables

I have a table invoices with a field invoice_number. This is what happens when i execute select invoice_number from invoice
invoice_number
1
2
3
5
6
10
11
I want a SQL that gives me the following result:
gap_start
gap_end
1
3
5
6
10
11
demo:db<>fiddle
You can use row_number() window function to create a row count and use the difference to your actual values as group criterion:
SELECT
MIN(invoice) AS start,
MAX(invoice) AS end
FROM (
SELECT
*,
invoice - row_number() OVER (ORDER BY invoice) as group_id
FROM t
) s
GROUP BY group_id
ORDER BY start

SQL query to find counts of numbers in running total

Suppose the table has 1 column ID and the values are as below:
ID
5
5
5
6
5
5
6
6
the output should be
ID count
5 3
6 1
5 2
6 2
How can we do that in a single SQL query.
If you want to find the Total count of the Records you have you can write like
select count(*) from database_name order by column_name;
In relational databases data in the table has no any order, see this: https://en.wikipedia.org/wiki/Table_(database)
the database system does not guarantee any ordering of the rows unless
an ORDER BY clause is specified in the SELECT statement that queries
the table.
therefore, in order to get desired results, you must have an additional colum in the table that defines an order of rows (and can by used in ORDER BY clause).
In the below examle cn column defines such an order:
select * from tab123 ORDER BY rn;
RN ID
---------- -------
1 5
2 5
3 5
4 6
5 5
6 5
7 6
8 6
Starting from Oracle version 12c new MATCH_REGOGNIZE clause can be used:
select * from tab123
match_recognize(
order by rn
measures
strt.id as id,
count(*) as cnt
one row per match
after match skip past last row
pattern( strt ss* )
define ss as ss.id = prev( ss.id )
);
On earlier versions that support windows function (Oracle 10 and above) you can use two windows functions: LAG ... over and SUM ... over, in this way
select max( id ) as id, count(*) as cnt
FROM (
select id, sum( xxx ) over (order by rn ) as yyy
from (
select t.*,
case lag( id ) over (order by rn )
when id then 0 else 1 end as xxx
from tab123 t
)
)
GROUP BY yyy
ORDER BY yyy;

SQL Max over multiple versions

I have a table with three columns
Product Version Price
1 1 25
1 2 15
1 3 25
2 1 8
2 2 8
2 3 4
3 1 25
3 2 10
3 3 5
I want to get the max price and the max version by product.
So in the above example the results would have product 1, version 3, price25. product 2, version 2, price 8.
Can you let me know how I would do this.
I'm on Teradata
If Teradata supports the ROW_NUMBER analytic function:
SELECT
Product,
Version,
Price
FROM (
SELECT
atable.*, /* or specify column names explicitly as necessary */
ROW_NUMBER() OVER (PARTITION BY Product
ORDER BY Price DESC, Version DESC) AS rn
FROM atable
) s
WHERE rn = 1
;
Using Teradata SQL this can be further simplified:
SELECT * FROM atable
QUALIFY
ROW_NUMBER()
OVER (PARTITION BY Product
ORDER BY Price DESC, Version DESC) = 1;
The QUALIFY is a Teradata extension to Standard SQL, it's similar to a HAVING for GROUP BY, it filters the result of a window function.
SELECT product
, max(version) as version
, max(price) as price
FROM mytable
GROUP BY product
Following code will select product, Highest value of version, Highest value of price and will sort at product using GROUP BY
SELECT [product], MAX([version]) as [MaxVersion], MAX([price]) as [MaxPrice]
FROM [NameOfTable]
GROUP BY [product]
More explanation on Max function:
Max function SQL
try this one
select p.Product, MAX(p.Price), (select MAX(Version) from Products where Product = p.Product and Price = MAX(p.price))
from Products as p
group by p.Product
it returns
(Product, price,version)
1 25 3 ,
2 8 2 ,
3 25 1

SQL Server 2005 query, update qtys to 0 where orderid <> min(orderid)

I have a table
OrderID Qty ShopID
-----------------------
1 50 10
1 50 11
2 10 15
2 10 18
The person ordered the same order at different shops (they will later decide which one will supply it), but I must only show one qty per order, please help setting the qty = 0 where the orderid is the same and shopid > min(shopID)
e.g.
OrderID Qty ShopID
-----------------------
1 50 10
1 0 11
2 10 15
2 0 18
This is just an example of the real world problem pls
You can try something like this:
;WITH CTE AS
(
SELECT
OrderID, Qty, ShopID,
RowNum = ROW_NUMBER() OVER (PARTITION BY OrderID ORDER BY ShopID DESC)
FROM
dbo.YourOrderTableHere
)
SELECT
OrderID,
OrderedQty = CASE RowNum
WHEN 1 THEN Qty ELSE 0
END,
ShopID
FROM CTE
Basically, I "partition" the data by OrderID - so each row within a given order gets assigned a consecutive RowNum.
In the select from the CTE (Common Table Expression), I return the quantity as stored in the table for the order with RowNum = 1, and I suppress that quantity and return 0 instead for all additional rows for that same OrderID.
This gives me an output of: