Last Invoice using Postgres - sql

I have a Postgres 9.1 database with three tables - Customer, Invoice, and Line_Items
I want to create a customer list showing the customer and last invoice date for any customer with a specific item (specifically all invoices that have the line_items.code beginning with 'L3').
First, I am trying to pull the one transaction for each customer (the last invoice with the 'L3" code) (figuring I can JOIN the customer names once this list is created).
Tables are something like this:
Customers
cust_number last_name first_name
=========== ======== ====================
1 Smith John
2 Jones Paul
3 Jackson Mary
4 Brown Phil
Transactions
trans_number date cust_number
=========== =========== ====================
1001 2014-01-01 1
1002 2014-02-01 4
1003 2014-03-02 2
1004 2014-03-06 3
Line_Items
trans_number date item_code
=========== =========== ====================
1001 2014-01-01 L3000
1001 2014-01-01 M2420
1001 2014-01-01 L3500
1002 2014-02-01 M2420
1003 2014-03-02 M2420
1004 2014-03-06 L3000
So far, I have:
Select transactions.cust_number, transactions.trans_number
from transactions
where transactions.trans_number in
( SELECT Line_Items.trans_number
FROM Line_Items
WHERE Line_Items.item_code ilike 'L3%'
ORDER BY line_items.date DESC
)
order by transactions.pt_number
This pulls all the invoices for each customer with an 'L3' code on the invoice, but I can't figure out how to just have the last invoice.

Use DISTINCT ON:
SELECT DISTINCT ON (t.cust_number)
t.cust_number, t.trans_number
FROM line_items l
JOIN transactions t USING (trans_number)
WHERE l.item_code ILIKE 'L3%'
ORDER BY t.cust_number, l.date DESC;
This returns at most one row per cust_number - the one with the latest trans_number. You can add more columns to the SELECT list freely.
Detailed explanation:
Select first row in each GROUP BY group?

you could use MIN or MAX:
SELECT Line_Items.trans_number, Max(line_items.date) As [last]
From Line_Items
Group By Line_Items.trans_number

Related

MS Access SQL, How to return only the newest row before a given date joined to a master table

I have two tables in a MS Access database as shown below. CustomerId is a primary key and fkCustomerId is a foreign key linked to the CustomerId in the other table.
Customer table
CustomerId
Name
1
John
2
Bob
3
David
Purchase table
fkCustomerId
OrderDate
fkStockId
1
01/02/2010
100
3
08/07/2010
101
2
14/01/2011
102
2
21/10/2011
103
3
02/03/2012
104
1
30/09/2012
105
3
01/01/2013
106
1
18/04/2014
107
3
22/11/2015
108
I am trying to return a list of customers showing the last fkStockId for each customer ordered before a given date.
So for the date 01/10/2012, I'd be looking for a return of
fkCustomerId
Name
fkStockId
1
John
105
2
Bob
103
3
David
104
A solution seems to be escaping me, any help would be greatly appreciated.
You can use nested select to get last order date.
SELECT Purchase.fkCustomerId,
Name,
fkStockId
FROM Purchase
JOIN
(
SELECT fkCustomerId,
MAX(OrderDate) as last_OrderDate
FROM Purchase
WHERE OrderDate < '01/10/2012'
GROUP BY fkCustomerId
) AS lastOrder
ON lastOrder.fkCustomerId = Purchase.fkCustomerId
AND last_OrderDate = OrderDate
LEFT JOIN Customer
ON Customer.CustomerId = Purchase.fkCustomerId
This example assumes OrderDate before '01/10/2012'. You might need to change it if you want it to be filtered by a different value.
Another assumption is that there's only one corresponding fkStockId for each OrderDate

SQL: Adding new column to show count of ID by date

I am hoping someone can help me with my query.
I have a table with the columns, 'Date', 'ID_Num and 'Name'. What I want to do is add a column at the end to show the total amount of times each ID_Num is within the data but based on the date. So although 'ID_Num' 1001 shows 4 times in total, it is twice on the 20/04/2018 and once on both the 21/04/2018 and 22/04/2018.
EDIT: I should have stipulated that I will be pulling several other columns with information, which I cant use a group by on everything.
Date ID_Num Name Count
20/04/2018 1001 John 2
20/04/2018 1001 John 2
20/04/2018 1002 Paul 2
20/04/2018 1002 Paul 2
20/04/2018 1003 David 2
20/04/2018 1003 David 2
20/04/2018 1004 Stephen 1
21/04/2018 1001 John 1
21/04/2018 1002 Paul 3
21/04/2018 1002 Paul 3
21/04/2018 1002 Paul 3
21/04/2018 1004 Stephen 1
22/04/2018 1001 John 1
22/04/2018 1002 Paul 1
22/04/2018 1003 David 1
22/04/2018 1004 Stephen 1
Thanks
Unless I'm missing something here, a simple group by and count should do it:
SELECT Date, ID_Num, Name, Count(*)
FROM TableName
GROUP BY Date, ID_Num, Name
(That is, assuming there can only be one Name for each ID_Num)
Update
Assuming your rdbms supports it, you can use count with an over clause:
SELECT Date, ID_Num, Name, Count(*) OVER(PARTITION BY Date, Id_Num)
FROM TableName
If not, you can use a sub query:
SELECT Date,
ID_Num,
Name,
(SELECT Count(*)
FROM TableName As t1
WHERE t1.Date = t0.Date
AND t1.ID_NUM = t0.ID_NUM)
FROM TableName As t0
Try this:
SELECT
Date,
Id_num,
count(*) count
FROM
tabel_name
GROUP BY
Date,
Id_num
If you want name as well:
SELECT
Date,
Id_num,
Name
count(*) count
FROM
tabel_name
GROUP BY
Date,
Id_num,
Name
You can use a normal select query and then add a sub query to do a group and show the total. Simple example below
SELECT Date, ID_Num, Name,
(SELECT Count(ID_Num) FROM TableName AS CHILD WHERE CHILD.Id_Num = Parent.Id_Num) AS Total
FROM TableName AS Parent

Concatenating data from one row into the results from another

I have a SQL Server database of orders I'm struggling with. For a normal order a single table provides the following results:
Orders:
ID Customer Shipdate Order ID
-----------------------------------------------------------------
1 Tom 2015-01-01 100
2 Bob 2014-03-20 200
At some point they needed orders that were placed by more than one customer. So they created a row for each customer and split the record over multiple rows.
Orders:
ID Customer Shipdate Order ID
-----------------------------------------------------------------
1 Tom 2015-01-01 100
2 Bob 2014-03-20 200
3 John
4 Dan
5 2014-05-10 300
So there is another table I can join on to make sense of this which relates the three rows which are actually one order.
Joint.Orders:
ID Related ID
-----------------------------------------------------------------
5 3
5 4
I'm a little new to SQL and while I can join on the other table and filter to only get the data relating to Order ID 300, but what I'd really like is to concatenate the customers, but after searching for a while I can't see how to do this. What'd I'd really like to achieve is this as an output:
ID Customer Shipdate Order ID
----------------------------------------------------------------
1 Tom 2015-01-01 100
2 Bob 2014-03-20 200
5 John, Dan 2014-05-10 300
You should consider changing the schema first. The below query might help you get a feel of how it can be done with your current design.
Select * From Orders Where IsNull(Customer, '') <> ''
Union All
Select ID,
Customer = (Select Customer + ',' From Orders OI Where OI.ID (Select RelatedID from JointOrders JO Where JO.ID = O.ID)
,ShipDate, OrderID
From Orders O Where IsNull(O.Customer, '') = ''

MS Access SQL Query - Showing total number of orders in a certain year

SQL appears to be more complex than I anticipated. My problem: for each customer, I would like to show the Customer ID and the total number of orders placed in 2011.
My table looks like this
Table: Order_t
Order_ID Order_Date Customer_ID
-------- ---------- -----------
1001 10/21/2011 1
1002 10/25/2011 8
1003 10/26/2011 15
1004 10/27/2011 5
1005 11/24/2011 3
1006 11/27/2011 2
1007 11/28/2011 11
1008 12/3/2011 12
1009 12/5/2011 1
1010 1/16/2012 4
I would like my query to display a table like this:
Customer_ID Orders_Placed
----------- -------------
1 2
2 1
3 1
5 1
8 1
11 1
12 1
15 1
My current query is this (I am currently completely neglecting the Date part because I haven't even figured out the grouping yet:
SELECT Customer_ID, SUM(Order_ID) AS Orders_Placed
FROM Order_t
GROUP BY Order_ID, Customer_ID
And this is my obviously wrong query:
Customer_ID Orders_Placed
----------- -------------
1 1001
8 1002
15 1003
5 1004
3 1005
2 1006
11 1007
12 1008
1 1009
4 1010
Thanks for help, but I would also like to understand where the problem is in my logic. What crucial part do I seem to not understand?
The problem with your logic is this
GROUP BY Order_ID, Customer_ID
Which means each combination of (Order_ID, Customer_ID) is put in a different GROUP. Since Order_ID alone is unique, practically no grouping is happening.
To do it correctly, you need to GROUP BY the Customer_ID (it reads like what you need, doesn't it), then COUNT the Orders. Finally, add the date filter as well.
SELECT Customer_ID, COUNT(Order_ID) AS Orders_Placed
FROM Order_t
WHERE Order_Date >= #1/1/2011# and Order_Date < #1/1/2012#
GROUP BY Customer_ID
Use count() instead
SELECT Customer_ID, COUNT(Order_ID) AS Orders_Placed
FROM Order_t
GROUP BY Customer_ID

SQL: How do I count the number of clients that have already bought the same product?

I have a table like the one below. It is a record of daily featured products and the customers that purchased them (similar to a daily deal site). A given client can only purchase a product one time per feature, but they may purchase the same product if it is featured multiple times.
FeatureID | ClientID | FeatureDate | ProductID
1 1002 2011-05-01 500
1 2333 2011-05-01 500
1 4458 2011-05-01 500
2 8888 2011-05-10 700
2 2333 2011-05-10 700
2 1111 2011-05-10 700
3 1002 2011-05-20 500
3 4444 2011-05-20 500
4 4444 2011-05-30 500
4 2333 2011-05-30 500
4 1002 2011-05-30 500
I want to count by FeatureID the number of clients that purchased FeatureID X AND who purchased the same productID during a previous feature.
For the table above the expected result would be:
FeatureID | CountofReturningClients
1 0
2 0
3 1
4 3
Ideally I would like to do this with SQL, but am also open to doing some manipulation in Excel/PowerPivot. Thanks!!
If you join your table to itself, you can find the data you're looking for. Be careful, because this query can take a long time if the table has a lot of data and is not indexed well.
SELECT t_current.FEATUREID, COUNT(DISTINCT t_prior.CLIENTID)
FROM table_name t_current
LEFT JOIN table_name t_prior
ON t_current.FEATUREDATE > t_prior.FEATUREDATE
AND t_current.CLIENTID = t_prior.CLIENTID
AND t_current.PRODUCTID = t_prior.PRODUCTID
GROUP BY t_current.FEATUREID
"Per feature, count the clients who match for any earlier Features with the same product"
SELECT
Curr.FeatureID
COUNT(DISTINCT Prev.ClientID) AS CountofReturningClients --edit thanks to feedback
FROM
MyTable Curr
LEFT JOIN
MyTable Prev WHERE Curr.FeatureID > Prev.FeatureID
AND Curr.ClientID = Prev.ClientID
AND Curr.ProductID = Prev.ProductID
GROUP BY
Curr.FeatureID
Assumptions: You have a table called Features that is:
FeatureID, FeatureDate, ProductID
If not then you could always create one on the fly with a temporary table, cte or view.
Then:
SELECT
FeatureID
, (
SELECT COUNT(DISTINCT ClientID) FROM Purchases WHERE Purchases.FeatureDate < Feature.FeatureDate AND Feature.ProductID = Purchases.ProductID
) as CountOfReturningClients
FROM Features
ORDER BY FeatureID
New to this, but wouldn't the following work?
SELECT FeatureID, (CASE WHEN COUNT(clientid) > 1 THEN COUNT(clientid) ELSE 0 END)
FROM table
GROUP BY featureID