SQL Server - Most recent date and sale amount columns - sql

I'm using SQL Server 2008 R2 to complete a query. I have a sale table that contains a unique sale id, a customer id, a sale date, and a sale amount. I'm trying to create a table that has the most recent sale for each customer and the amount for that sale.
| customer_id | most recent sale date | sale amount |
| 1 |2012-06-11 00:00:00.000| 150 |
| 2 |2012-01-07 00:00:00.000| 55 |
| 3 |2012-02-18 00:00:00.000| 117 |
| 4 |2012-09-02 00:00:00.000| 25 |
I have the first two columns with this query:
SELECT DISTINCT customer_id, MAX(sale_date)
FROM sale
GROUP BY customer_id
When I try to add the amount of the sale, everything I try includes every sale for that customer, not just the most recent one. Is there a way to do this? Keep in mind there is a unique sale id on this table that might be of some use. Thank you for your time.

You can use ROW_NUMBER with PARTITION BY in a CTE:
WITH CTE AS
(
SELECT sale_id,customer_id,sale_date, sale_amount
, RN = ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY sale_date DESC)
FROM sale
)
SELECT sale_id, customer_id, sale_date, sale_amount
FROM CTE
WHERE RN = 1
Here's a sample fiddle: http://sqlfiddle.com/#!3/513280/1/0

SELECT a.customer_id, a.sale_date, a.sale_amount
FROM sale a
INNER JOIN
(
SELECT customer_id, MAX(sale_date) maxSale
FROM sale
GROUP BY customer_id
) b ON a.customer_ID = b.customer_ID AND
a.sale_date = b.maxSale

By just using Aggregate function MAX in an independent subquery worked for me.
SELECT Customerid, Saleid, Sldate AS 'Most Recent Sale', Saleamount
FROM Sale S1
WHERE Sldate = (SELECT MAX(Sldate) FROM Sale S2);
Using Aliases is a mandatory step.
Hope this helps!

SELECT CUSTOMER_ID,SALE_AMOUNT,SALEDATE FROM SALE WHERE SALEDATE =(SELECT MAX(SALEDATE) FROM SALE);

Related

PostgreSQL list companies and rank by sales

So I have:
companies (id, name, tenant_id)
invoices (id, company_id, tenant_id, total)
What I want to do is return a result set like:
company | Feb Sales | Feb Rank | Lifetime Sales | Lifetime Rank
-----------------------------------------------------------------------
ABC Comp | 1,000 | 1 | 2,000 | 2
XYZ Corp | 500 | 2 | 5,000 | 1
I can do the sales totals using subselects, but when I do the rank always returns 1. I'm assuming because it only returns 1 row per subselect so will always be the top row?
Here is a piece of the sql:
SELECT
"public".companies."name",
(
SELECT
rank() OVER (PARTITION BY i.tenant_id ORDER BY sum(grand_total) DESC) AS POSITION
FROM
invoices i
where
company_id = companies.id
group by
i.tenant_id, i.company_id
)
from companies
Below is untested version that can have typos. Please treat it just as description of the approach. For simplicity I assumed that invoices have a month column.
SELECT
"public".companies."name",
rank() OVER (PARTITION BY sales.companies ORDER BY sales.lifetime) As "Lifetime Rank",
rank() OVER (PARTITION BY sales.companies ORDER BY sales.month As "One Month"
FROM companies LEFT JOIN
(
SELECT
SUM(grand_total) As Lifetime,
SUM(CASE WHEN i.month = <the month of report>, grand_total, 0) As Month
FROM
invoices i
GROUP BY company_id
) sales
ON companies.company_id = sales.company_id
If you run into problems, add the actual code that you used and sample data to your post and I will attempt to create a live demo for you.

SQL find which products appear every week

I have some queries that return lists of products for a time period, and I want to find out which products appear in all of those time periods.
WeekEnding | Product
07/07/14 | A
07/07/14 | B
07/07/14 | C
14/07/14 | A
14/07/14 | B
21/07/14 | A
21/07/14 | B
21/07/14 | C
So in the above example data I would have products A, and B which are in all 3 weeks, and I could imagine running a query like
SELECT Product FROM ProductWeek
GROUP BY Product
HAVING COUNT(*) = (
SELECT COUNT(distinct weekending) from ProductWeek )
Unfortunately I am writing this query in MSAccess, so count distinct is not available, but at any rate it feels like there should be a more elegant solution to this problem
You can do it with a subquery:
SELECT Product
FROM ProductWeek
GROUP BY Product
HAVING COUNT(*) = (SELECT COUNT(*) from (SELECT distinct weekending from ProductWeek ) as t);

Get the results of a subquery in SQL

How do you create a join to get the latest invoice for all customers?
Tables:
- Invoices
- Customers
Customers table has: id, last_invoice_sent_at, last_invoice_guid
Invoices table has: id, customer_id, sent_at, guid
I'd like to fetch the latest invoice for every customer and, with that data, update last_invoice_sent_at and last_invoice_guid in the Customers table.
You want to use distinct on. For a query soring by customer_id and then by invoice, it would return the first row for each distinct value indicated in distinct on. That is the rows with * below:
customer_id | sent_at |
1 | 2014-07-12 | *
1 | 2014-07-10 |
1 | 2014-07-09 |
2 | 2014-07-11 | *
2 | 2014-07-10 |
So your update query could look like:
update customers
set last_invoice_sent_at = sent_at
from (
select distinct on (customer_id)
customer_id,
sent_at
from invoices
order by customer_id, sent_at desc
) sub
where sub.customer_id = customers.customer_id
#Konrad provided a flawless SQL statement. But since we are only interested in a single column, GROUP BY will be more efficient than DISTINCT ON (which is great to retrieve multiple columns from the same row):
UPDATE customers c
SET last_invoice_sent_at = sub.last_sent
FROM (
SELECT customer_id, max(sent_at) AS last_sent
FROM invoices
GROUP BY 1
) sub
WHERE sub.customer_id = c.customer_id;

SQL Query - Sum of Order tha Contain an Item

I am surprised I have not been able to find a solution to this. We have a table
ORDER # | PRODUCT ID | PRICE
1 | 1 | 1.00
1 | 2 | 2.00
2 | 3 | 3.00
2 | 4 | 4.00
3 | 1 | 5.00
3 | 4 | 6.00
We want to capture the sum of the revenues of all orders which included productID=1. The result in this example should be 1+2+5+6 = 14
What is the best way to achieve this?
Currently, best solution I have is to run two queries.
1 - SELECT orderID FROM table WHERE prodID=$prodID
2 - SELECT price FROM table WHERE orderID=[result of the above]
This has worked, but would strongly prefer to have a single query.
Here is a query that gives the results you are looking for:
SELECT OrderNum, SUM(PRICE) as TotalPrice
FROM MyTable AS M
WHERE EXISTS (SELECT 1 -- Include only orders that contain product 1
FROM MyTable AS M2
WHERE M2.OrderNum=M.OrderNum AND M2.ProductId=1)
GROUP BY OrderNum
Try:
select sum(price) as total_price
from orders
where prod_order in
(select prod_order
from orders
where product_id = 1)
Check this SQLFiddle to confirm the result.
select sum(price) as total_price where product_id=[enter here id];
SELECT SUM(t1.price) FROM tableName t1 WHERE
t1.orderId IN (SELECT t2.orderId FROM tableName t2 WHERE
t2.productId=productIdYouWant)
If you need more informations on how this work, please feel free to ask.
You need a nested select. The inner select should give you the total order value;
select order, sum(price) as totalvalue from table group by order
Now you need to select the orders which have a product id of 1, and sum the order price;
select sum(totalvalue) from (
select order, sum(price) as totalvalue from table group by order
) where order in (
select order from table where productid = 1
)

Aggregate highest prices per client of salesmen

I have a table like this:
SELECT * FROM orders;
client_id | order_id | salesman_id | price
-----------+----------+-------------+-------
1 | 167 | 1 | 65
1 | 367 | 1 | 27
2 | 401 | 1 | 29
2 | 490 | 2 | 48
3 | 199 | 1 | 68
3 | 336 | 2 | 22
3 | 443 | 1 | 84
3 | 460 | 2 | 92
I want to find the an array of order_ids for each of the highest priced sales for each unique salesman and client pair. In this case I want the resulting table:
salesman_id | order_id
-------------+----------------
1 | {167, 401, 443}
2 | {490, 460}
So far I have an outline for a query:
SELECT salesman_id, max_client_salesman(order_id)
FROM orders
GROUP BY salesman_id;
However I'm having trouble writing the aggregate function max_client_salesman.
The documentation online for aggregate functions and arrays in postgres is very minimal. Any help is appreciated.
Standard SQL
I would combine the window function last_value() or firstvalue() with DISTINCT to the get the orders with the highest price per (salesman_id, client_id) efficiently and then aggregate this into the array you are looking for with the simple aggregate function array_agg().
SELECT salesman_id
,array_agg(max_order_id) AS most_expensive_orders_per_client
FROM (
SELECT DISTINCT
salesman_id, client_id
,last_value(order_id) OVER (PARTITION BY salesman_id, client_id
ORDER BY price
ROWS BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING) AS max_order_id
FROM orders
) x
GROUP BY salesman_id
ORDER BY salesman_id;
Returns:
salesman_id | most_expensive_orders_per_client
-------------+------------------------------------
1 | {167, 401, 443}
2 | {490, 460}
SQL Fiddle.
If there are multiple highest prices per (salesman_id, client_id), this query pick only one order_id arbitrarily - for lack of definition.
For this solution it is essential to understand that window functions are applied before DISTINCT. How you to combine DISTINCT with a window function:
PostgreSQL: running count of rows for a query 'by minute'
For an explanation on ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING refer to this closely related answer on dba.SE.
Simper with non-standard DISTINCT ON
PostgreSQL implements, as extension to the SQL standard, DISTINCT ON. With it you can very effectively select rows unique according to a defined set of columns.
It won't get simpler or faster than this:
SELECT salesman_id
,array_agg(order_id) AS most_expensive_orders_per_client
FROM (
SELECT DISTINCT ON (1, client_id)
salesman_id, order_id
FROM orders
ORDER BY salesman_id, client_id, price DESC
) x
GROUP BY 1
ORDER BY 1;
SQL Fiddle.
I also use positional parameters for shorter syntax. Details:
Select first row in each GROUP BY group?
I think you want the Postgres function array_agg in combination with row_number() However, your description of the query does not make sense to me.
The following gets clients and salesmen and the list of orders for the highest priced order by salesman:
select client_id, salesman_id, array_agg(order_id)
from (select o.*,
row_number() over (partition by salesman_id order by price desc) as sseqnum,
row_number() over (partition by client_id order by price desc) as cseqnum
from orders o
) o
where sseqnum = 1
group by salesman_id, client_id
I don't know what you mean by "highest priced sales for each salesman and client". Perhaps you want:
where sseqnum = 1 or cseqnum = 1