SQL Server sum with a where or having condition - sql

I'm hoping this makes sense as what I'm trying to do is SUM rows based on other columns of existing rows. I have tried a couple different ways and what I hope is now close is what I have here. This is not my full SQL but hopefully this small example will get me on track
SELECT Price,SUM(Item) from table where Price >= Price group by Price
Sample Data
| PRICE | ITEM |
|-------|-------|
| 1.00 | 5 |
| 2.00 | 9 |
| 3.00 | 2 |
Hopeful Result
| PRICE | ITEM |
|-------|-------|
| 1.00 | 5 |
| 2.00 | 14 |
| 3.00 | 16 |
The actual result is more or less the sample data which I would expect as I am grouping by Price so it makes sense that it returns the rows like this. I just can't seem to think of away to include Price in my select without having to group or use an aggregate on it. I'm thinking I could maybe do this type of calculation with an inner select but I'm hoping there is a different way as my actual query has a lot of joins which could get messy if I go this route.
Thanks for any help.

If you're using SQL server 2012...
Select price, item, sum(item) OVER(order by price rows unbounded preceding) as runningtotal
from sample
http://sqlfiddle.com/#!6/36e9f/1/0

You can accomplish this with a sub-query, but a more efficient way might be to use a CROSS/OUTER APPLY. It depends on your specific data. I provide both methods of doing that below... See which one runs faster based on your specific data.
Sub-query method
SELECT DISTINCT op.Price, (SELECT SUM(ip.Item) FROM table ip WHERE ip.Price <= op.Price) as ITEM FROM table op ORDER BY op.Price ASC
Outer-apply method
SELECT DISTINCT op.Price, a.Items
FROM table op
OUTER APPLY (SELECT SUM(ip.Item) as Items FROM TABLE ip WHERE ip.Price <= op.Price) a
ORDER BY op.Price ASC

Probably you are trying to do something like below. use a self join with the same table.
See a DEMO Here
SELECT t1.Price, SUM(t2.Item)
FROM table1 t1,
table1 t2
WHERE t2.Price <= t1.Price
GROUP BY t1.Price
ORDER BY t1.price;

Related

Filter between date in sum by group in sql from two different tables data

How are you, I have two tables one tables is PRODUCT and other tables is STOCK_sales, i use sum and group by,
But my problem is i can't not filter between dates.
in this link is my SQL database CODE and all structure how can i do this.
myquery
SELECT
Product.ProductID,buyprice,sellprice, SUM(sellqty) as Total
FROM product,Stock_sales
WHERE Product.ProductID=Stock_sales.ProductID
GROUP BY Product.ProductID,buyprice,sellprice
ORDER BY Product.ProductID
THANK YOU.
https://dbfiddle.uk/?rdbms=postgres_11&fiddle=f2b78aab10cf770bc918206da6aaeecd
You can use a where clause to filter the dates and other columns.
your FROM clause sould be wriiten by JOINS, your style is outdated for years
SELECT Product.ProductID,buyprice,sellprice,
SUM(sellqty) as Total
FROM product INNER JOIN Stock_sales ON Product.ProductID=Stock_sales.ProductID
WHERE data BETWEEN '2022-01-01' AND '2022-01-04'
GROUP BY Product.ProductID,buyprice,sellprice
ORDER BY Product.ProductID
productid | buyprice | sellprice | total
--------: | -------: | --------: | ----:
1 | 10 | 20 | 20
db<>fiddle here
I agree with the answer by nbk.
However, if you want to continue with the WHERE clause specifying the key IDs instead of using a JOIN then you just need to extend that using AND:
WHERE Product.ProductID=Stock_sales.ProductID
AND stock_sales.data = '2022-01-03'
or
WHERE Product.ProductID=Stock_sales.ProductID
AND stock_sales.data BETWEEN '2022-01-03' AND '2022-01-17'

One one customer from table

I need help using Teradata SQL and I hope you can help.
I have a table that looks like this:
email | article number | discount | price
customer01#test.de | 123 | 15 | 999
customer01#test.de | 456 | 30 | 1999
customer01#test.de | 789 | 30 | 999
From this table I want only row from the customer which has the highest discount and (if there are multiple rows with the same discount) the lowest price.
So in the example above, I only want the 3rd line. How can I write a SQL query for this?
The most flexible way utilizes ROW_NUMBER:
select * from myTable
QUALIFY
ROW_NUMBER()
OVER (PARTITION BY email -- for each customer, otherwise remove it
ORDER BY discount DESC, price ASC) = 1
The simplest way to do this is via a simple select statement ordered by discount (descending) and then by price (ascending).
SELECT * FROM customers
ORDER BY discount DESC, price ASC
LIMIT 1
Use NOT EXISTS to return a row only if there are no other row with a higher discount, or another row with same discount and a lower price.
select *
from tablename t1
where not exists (select 1 from tablename t2
where t2.discount > t1.discount
or (t2.discount = t1.discount and t2.price < t1.price))

How to get only those rows where the next row (by datestamp) has a different property in some field?

I have a table of data like this:
+--------------+-------------------------+----------+
| o_objguid | o_acttime | o_action |
+--------------+-------------------------+----------+
| 478n8937g990 | 2013-10-02 10:45:33.423 | 1012 |
| 478n8937g990 | 2013-10-02 11:21:57.207 | 1012 |
| 478n8937g990 | 2013-10-02 11:21:57.887 | 1012 |
| 478n8937g990 | 2013-11-15 13:42:11.983 | 1013 |
+--------------+-------------------------+----------+
I want a query to return only those rows where, for a given o_objguid, the next row in time sequence does not have an o_action of 1012.
I'm using the following query:
select d1.* from dbo.dms_audt d1
inner join
(select d2.o_objguid,d2.o_acttime,d2.o_action,
min(datediff(second,d1.o_acttime,d2.o_acttime)) as intervalToNext
from dbo.dms_audt d1
inner join
dbo.dms_audt d2
on
d1.o_objguid=d2.o_objguid
where
d2.o_acttime>d1.o_acttime
group by
d2.o_objguid,d2.o_acttime,d2.o_action) d2
on
d1.o_objguid=d2.o_objguid
where
datediff(second,d1.o_acttime,d2.o_acttime)=intervalToNext
and
d1.o_action=1012
and
d2.o_action<>1012
This query does not return the row with an o_acttime of 2013-10-02 10:45:33.423, because the next row has the same o_action. But because I'm using an argument of second in the datediff() function, the rows with these o_acttime:
2013-10-02 11:21:57.207
2013-10-02 11:21:57.887
are both treated as the same date value for calculation purposes, so both rows are returned, when really the only one that should be returned is the 2013-10-02 11:21:57.887 row.
I tried changing the datediff() argument to millisecond, but this resulted in an overflow error, probably because a date difference of several days or more will have too many milliseconds to fit in the return type.
I guess I can join the query's results against another query that will use max(o_acttime), so that only the highest o_acttime in a group of results that have the same intervalToNext will be returned. But I'm concerned about the size and performance of this query; there are a lot of nested Cartesian products here and it's already pretty slow against a set of 1000000+ rows. Is there a better way to get the result I want?
This should work as well without computing a CTE twice. Depending on the data and indexing strategy it may or may not be faster than Joachim's response.
SELECT
*
FROM dbo.dms_audt d1
CROSS APPLY ( -- get next action
SELECT TOP 1
*
FROM dbo.tbl_audt X
WHERE d1.o_objguid = X.o_objguid
AND d1.o_acttime < X.o_acttime
ORDER BY X.o_acttime
) D2
WHERE D1.o_action = 1012
AND D2.o_action != 1012
Sadly, SQL Server 2008 does not have LEAD() (a 2012 feature) which would have made the query trivial, but you can simulate it using ROW_NUMBER();
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY o_acttime) rn
FROM table1
WHERE o_objguid = '478n8937g990'
)
SELECT a.*
FROM cte a
JOIN cte b
ON a.rn = b.rn - 1 AND b.o_action <> 1012;
An SQLfiddle to test with.

Comparing in SQL and SUM

I really couldn't figure out a good title for this question, but I have a problem that I'm sure you can help me with!
I have a query which outputs something like this:
Month | Year | Subcategory | PrivateLabel | Price
-------------------------------------------------
1 | 2010 | 666 | No | -520
1 | 2010 | 666 | No | -499,75
1 | 2010 | 666 | No | -59,95
1 | 2010 | 666 | No | -49,73
1 | 2010 | 666 | No | -32,95
I want to SUM on the price because all the other data is the same. I thought I could do this with SUM and GROUP BY, but I can't figure out how to do it or at least it doesn't output the right result.
The query is an inner join between two tables, if that helps.
select
month
,year
,subcategory
,privatelabel
,sum(price) as [total sales]
from
a inner join b ...
where
any where clauses
group by
month
,year
,subcategory
,privatelabel
should work if i am understanding you correctly.. every colum in the select either needs to be part of the group by or an aggregate function on all rows in the group
added a fiddle.. mainly as i didn't know about he text to DDL functionality and wanted to test it ;-) (thanks Michael Buen)
http://sqlfiddle.com/#!3/35c1c/1
note the where clause is a place holder..
select month, year, subcategory, privatelabel, sum(price)
from (put your query in here) dummyName
group by month, year, subcategory, privatelabel
Basic idea is it will run your current query to get above output then do the sum and group by on the result.
You query has to be in parentheses and you have to give it some name e.g. dummyName. As long as it's unique in the sql and preferably not a key word, doesn't matter what it is.
There might be a way of doing all this in one go, but without the sql for your query we can't help.

SQL to find the date when the price last changed

Input:
Date Price
12/27 5
12/21 5
12/20 4
12/19 4
12/15 5
Required Output:
The earliest date when the price was set in comparison to the current price.
For e.g., price has been 5 since 12/21.
The answer cannot be 12/15 as we are interested in finding the earliest date where the price was the same as the current price without changing in value(on 12/20, the price has been changed to 4)
This should be about right. You didn't provide table structures or names, so...
DECLARE #CurrentPrice MONEY
SELECT TOP 1 #CurrentPrice=Price FROM Table ORDER BY Date DESC
SELECT MIN(Date) FROM Table WHERE Price=#CurrentPrice AND Date>(
SELECT MAX(Date) FROM Table WHERE Price<>#CurrentPrice
)
In one query:
SELECT MIN(Date)
FROM Table
WHERE Date >
( SELECT MAX(Date)
FROM Table
WHERE Price <>
( SELECT TOP 1 Price
FROM Table
ORDER BY Date DESC
)
)
This question kind of makes no sense so im not 100% sure what you are after.
create four columns, old_price, new_price, old_date, new_date.
! if old_price === new_price, simply print the old_date.
What database server are you using? If it was Oracle, I would use their windowing function. Anyway, here is a quick version that works in mysql:
Here is the sample data:
+------------+------------+---------------+
| date | product_id | price_on_date |
+------------+------------+---------------+
| 2011-01-01 | 1 | 5 |
| 2011-01-03 | 1 | 4 |
| 2011-01-05 | 1 | 6 |
+------------+------------+---------------+
Here is the query (it only works if you have 1 product - will have to add a "and product_id = ..." condition on the where clause if otherwise).
SELECT p.date as last_price_change_date
FROM test.prices p
left join test.prices p2 on p.product_id = p2.product_id and p.date < p2.date
where p.price_on_date - p2.price_on_date <> 0
order by p.date desc
limit 1
In this case, it will return "2011-01-03".
Not a perfect solution, but I believe it works. Have not tested on a larger dataset, though.
Make sure to create indexes on date and product_id, as it will otherwise bring your database server to its knees and beg for mercy.
Bernardo.