SQL query aggregate function with two tables - sql

I'm trying to query some data from SQL such that it sums some columns, gets the max of other columns and the corresponding value from another table. For example,
|table1|
|order id| |id| |shares| |date| other stuff
12345 1 100 05/13/16 XXX
12345 2 200 05/15/16 XXX
12345 3 300 06/12/16 XXX
12345 4 400 02/22/16 XXX
56789 5 1000 03/30/16 XXX
56789 6 200 02/25/16 XXX
22222 7 5000 01/10/16 XXX
|table2|
|id| |price|
1 21.2
2 20.2
3 19.1
4 21.3
5 100.0
6 110.0
7 5.0
I want my output to be:
|shares| |date| |price| other stuff
1000 06/12/16 19.1 max(other stuff)
1200 03/30/16 1000.0 max(other stuff)
5000 01/10/16 5.0 max(other stuff)
The shares have been summed up, the date is max(date), and the price is the price at the corresponding max(date).
So far, I have:
select
orderid, stock, side, exchange,
max(startdate), max(enddate),
sum(shares), sum(execution_price * shares) / sum(shares),
max(limitprice), max(price)
from
table1 t1
inner join
table2 t2 on t2.id = t1.id
where
location = 'CHICAGO'
and startdate > '1/1/2016'
and order_type = 'limit'
group by
orderid, stock, side, exchange
However, this returns:
|shares| |date| |price| |other stuff|
1000 06/12/16 21.3 max(other stuff)
1200 03/30/16 1100.0 max(other stuff)
5000 01/10/16 5.0 max(other stuff)
which isn't the corresponding price for the max(date).
The only link between the two datasets are their id numbers, which is why
inner join
table2 t2 on t2.id = t1.id
is done. No dates in the second table at all. Any help?
Thanks.

You can resolve this using Sub-query. You need not use any aggregate function on price column, just find the max date and then get price of that particular date.Try something like this..
select t5.*, t4.price
from
(select t1.order_id, sum(t1.shares) as shares, max(t1.date) as maxdate, max(other_stuff) as other_stuff
from Table1 t1
inner join
Table2 t2 on t2.id = t1.id
group by t1.order_id) t5
inner join Table1 t3
on t5.maxdate = t3.date and t5.order_id = t3.order_id
inner join Table2 t4
on t3.id = t4.id;
ONLINE DEMO HERE

Try this (don't forget to replace #table1 and #table2 with your own table names):
SELECT Aggregated.shares
, Aggregated.date
, Aggregated.other_stuff
, T2.price
FROM (
SELECT order_id
, SUM(shares) as shares
, MAX(date) as date
, MAX(other_stuff) as other_stuff
FROM #table1 AS T1
GROUP BY order_id
) AS Aggregated
INNER JOIN #table1 AS T1 ON Aggregated.order_id = T1.order_id AND Aggregated.date = T1.date
INNER JOIN #table2 AS T2 ON T2.id = T1.id

So, before I write you a query, you basically want the price during that max date, correct? You have MAX on price, sum of shares, max on limit price, sum on shares again and so on.
My guess is you want the latest price based on the latest date (Max) then run the calculations for the latest date, latest # of shares for that max date, and sum that all together? You're also grouping on ID, Shares, and other things that don't really make sense, it would seem you would want to group on Shares, Side and Exchange but not ID. Looks like you put a max on other things just so they show up without having to group on them, this is not going to work for what you want as long as I think I know what you're looking for =) Let me know and I can definitely help if I know what your end result "specs" are.

I would do a sub-query with a max over partition ordered by date to display the last date price, then do the aggregations on the upper level, here is an example of how it would work.
Sample data
pk id shares date id price
------- --- -------- -------------------------- --- -------
100 1 100 2016-07-08 10:40:34.707 1 50
100 2 200 2016-07-06 10:40:34.707 2 20
101 3 500 2016-07-09 10:40:34.707 3 70
101 4 150 2016-07-07 10:40:34.707 4 80
102 5 300 2016-07-10 10:40:34.707 5 40
Query
with t1 as (
select 100 pk,1 id, 100 shares, getdate()-3 date union all
select 100 pk,2 id, 200 shares, getdate()-5 date union all
select 101 pk,3 id, 500 shares, getdate()-2 date union all
select 101 pk,4 id, 150 shares, getdate()-4 date union all
select 102 pk,5 id, 300 shares, getdate()-1 date ),
t2 as (
select 1 id, 50 price union all
select 2 id, 20 price union all
select 3 id, 70 price union all
select 4 id, 80 price union all
select 5 id, 40 price
)
SELECT pk,sum(shares) shares,max(date) date, max(price) from(
SELECT pk,
shares,
date,
MAX(price) over(partition by pk order by date desc) price
FROM t1
JOIN t2 ON t1.id = t2.id) a
group by pk
Result
pk shares date Price
--- ------- ------------------------ -----
100 300 2016-07-08 10:51:16.023 50
101 650 2016-07-09 10:51:16.023 80
102 300 2016-07-10 10:51:16.023 40

Related

Query to calculate the sum from 3 different tables

I have 3 tables
Table A:
Cid acc_id acc balance
1 345 100
1 456 300
2 347 500
Table B:
Cid acc_id acc balance
1 348 100
1 457 300
2 349 500
Table C:
Cid acc_id acc balance
1 340 100
1 457 300
2 344 500
I need to create a single table which gives the sum of balances for each customer across all 3 tables.
Cid. Balance
1. 1200
2. 1500
I need SQL for this purpose. Since customer id is repeating within the table I m confused.
Use union all and aggregation
select cid, sum(balance)
from ((select Cid, acc_id, balance
from a
) union all
(select Cid, acc_id, balance
from b
) union all
(select Cid, acc_id, balance
from c
)
) abc
group by cid;
You can use UNION ALL, as in:
select
cid,
sum(balance) as balance
from (
select * from table_a
union all
select * from table_b
union all
select * from table_c
) x
group by cid

How to use this in sql -- > max(sum (paid * quantity )) to solve a query

How to get the max value order of each customer ?
select num, max(sum(paid*quantity))
from orders join
pizza
using (order#)
group by customer#;
table
num orderN price
-------- --- -------
1 109 30
1 118 25
3 101 30
3 115 27
4 107 23
5 100 17
5 129 16
output req-
num Pnum price
-------- --- -------
1 109 30
3 101 30
4 107 23
5 100 17
You want to select the record having the highest price in each group of nums.
If your RDBMS supports window functions, that's straight forward with ROW_NUMBER() :
SELECT num, pnum, price
FROM (
SELECT t.*, ROW_NUMBER OVER(PARTITION BY num ORDER BY price DESC) rn
FROM mytable t
) x
WHERE rn = 1
Else, you can take the following approach, that uses a NOT EXISTS condition with a correlated subquery to ensure that the record being joined in the one with the highest price for the current num :
SELECT num, pnum, price
FROM mytable t
WHERE NOT EXISTS (
SELECT 1 FROM mytable t1 WHERE t1.num = t.num AND t1.price > t.price
)

Select except where different in SQL

I need a bit of help with a SQL query.
Imagine I've got the following table
id | date | price
1 | 1999-01-01 | 10
2 | 1999-01-01 | 10
3 | 2000-02-02 | 15
4 | 2011-03-03 | 15
5 | 2011-04-04 | 16
6 | 2011-04-04 | 20
7 | 2017-08-15 | 20
What I need is all dates where only one price is present.
In this example I need to get rid of row 5 and 6 (because there is two difference prices for the same date) and either 1 or 2(because they're duplicate).
How do I do that?
select date,
count(distinct price) as prices -- included to test
from MyTable
group by date
having count(distinct price) = 1 -- distinct for the duplicate pricing
The following should work with any DBMS
SELECT id, date, price
FROM TheTable o
WHERE NOT EXISTS (
SELECT *
FROM TheTable i
WHERE i.date = o.date
AND (
i.price <> o.price
OR (i.price = o.price AND i.id < o.id)
)
)
;
JohnHC answer is more readable and delivers the information the OP asked for ("[...] I need all the dates [...]").
My answer, though less readable at first, is more general (allows for more complexes tie-breaking criteria) and also is capable of returning the full row (with id and price, not just date).
;WITH CTE_1(ID ,DATE,PRICE)
AS
(
SELECT 1 , '1999-01-01',10 UNION ALL
SELECT 2 , '1999-01-01',10 UNION ALL
SELECT 3 , '2000-02-02',15 UNION ALL
SELECT 4 , '2011-03-03',15 UNION ALL
SELECT 5 , '2011-04-04',16 UNION ALL
SELECT 6 , '2011-04-04',20 UNION ALL
SELECT 7 , '2017-08-15',20
)
,CTE2
AS
(
SELECT A.*
FROM CTE_1 A
INNER JOIN
CTE_1 B
ON A.DATE=B.DATE AND A.PRICE!=B.PRICE
)
SELECT * FROM CTE_1 WHERE ID NOT IN (SELECT ID FROM CTE2)

How to Filter records with some column with similar value and some not

I have the following table A
Table A
ID Date Price
123 4/1/2015 300
123 4/1/2015 500
456 4/1/2015 200
456 5/1/2015 200
789 6/1/2015 300
368 NULL 700
Scenario: I want to pull all those records where date is same but price is not same:
for example:
ID Date Price
123 4/1/2015 300
123 4/1/2015 500
select t1.*
from your_table t1
join
(
select id
from your_table
group by id, date
having count(distinct price) > 1
) t2 on t1.id = t2.id
One method uses analytic functinos:
select t.*
from (select t.*, min(price) over (partition by id, date) as minprice,
max(price) over (partition by id, date) as maxprice
from t
) t
where minprice <> maxprice;
Another uses a simple exists:
select t.*
from t t
where exists (select 1 from t t2 where t2.id = t.id and t2.date = t.date);
Both of these methods assume that date has no time component. If it does, then use trunc(date) or similar logic.

SQL Server 2005 MAX, SUM AND GROUP BY

I am using SQL Server 2005 and I have a problem with my SQL query. Basically, I want to get the total amount of all transactions of customers, grouped by company, based on the latest dates from all customer transactions.
Sample data:
Customer_Id Date Amount COMPANY
-------------------------------------------------
1 3/3/2014 9021 COMPANY X
2 3/3/2014 12000 COMPANY Y
2 3/15/2014 10000 COMPANY Y
2 3/30/2014 8000 COMPANY Y
4 3/13/2014 10000 COMPANY Z
5 3/14/2014 1400 COMPANY X
1 3/16/2014 2500 COMPANY X
7 3/14/2014 110 COMPANY Y
3 3/17/2014 1500 COMPANY Z
2 3/19/2014 2044 COMPANY Y
3 3/09/2014 9400 COMPANY Z
3 3/11/2014 8950 COMPANY Z
2 3/31/2014 3455 COMPANY Y
3 3/15/2014 950 COMPANY Z
6 3/15/2014 5543 COMPANY X
What I want to accomplish is like this:
COMPANY TOTAL
COMPANY X 9443 --> sum from customer_id 1 (2500, as of 3/16/2014) and customer_id 6 (5542, 3/15/2014) and customer_id 5 (1400 as of 3/14/2014)
COMPANY Y 3455 --> sum from customer_id 2 (3455, as of 3/31/2014)
COMPANY Z 10950 --> sum from customer_id 4 (1000, as of 3/13/2014) and customer_id 3 (950, as of 3/15/2014)
Below are some SQL queries I've tried which doesn't work on my goal:
SELECT TOP (1) WITH TIES
Date, Company, SUM(Amount) AS total
FROM
tbl_Table
GROUP BY
Date, Company
ORDER BY
Date DESC
SELECT
t1.Date, t1.Company, SUM(t1.Amount) AS total
FROM
tbl_Table AS t1
INNER JOIN
(SELECT
MAX(Date) AS date, Company
FROM
tbl_Table
GROUP BY
Company) AS t2 ON t1.Date = t2.Date AND t1.Company = t2.Company
GROUP BY
t1.Date, t1.Company
WITH latest AS
(SELECT
Company, MAX(Date) AS maxdate
FROM
tbl_Table
GROUP BY
Company
)
SELECT
a.Date, a.Company, SUM(a.Amount) AS total
FROM
tbl_Table AS a
INNER JOIN
latest AS b ON a.Company = b.Company AND a.Date = b.maxdate
GROUP BY
a.Date, a.Company
Your results are still not correct by data you give.
SQLFIDDLEExample
Query:
SELECT t1.Company,
SUM(t1.Amount) Total
FROM Table1 t1
LEFT JOIN Table1 t2
ON t1.COMPANY = t2.COMPANY
AND t1.Customer_Id = t2.Customer_Id
AND t1.Date < t2.Date
WHERE t2.Customer_Id is null
GROUP BY t1.Company
Result:
| COMPANY | TOTAL |
|-----------|-------|
| COMPANY X | 9443 |
| COMPANY Y | 3565 |
| COMPANY Z | 11500 |
Try This
WITH cte AS (
SELECT Amount,Company,
ROW_NUMBER() OVER (PARTITION BY Customer_Id ORDER BY CAST([Date] AS DATETIME) desc )
AS dateRowRank
)
SELECT Company,SUM(Amount)
FROM cte
WHERE dateRowRank=1
GROUP BY Company