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

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

Related

How do I return a key value when a specific column value is NOT present?

Here's a simplified example of my SALESORDERLINES table:
ORDER
LINE
ITEM
100
1
ITEMA
100
2
ITEMB
100
3
FEE
101
1
ITEMA
101
2
FEE
102
1
ITEMC
102
2
ITEMD
102
3
ITEME
103
1
ITEMA
103
2
FEE
104
1
ITEMB
104
2
ITEMC
The key values for the table are ORDER and LINE.
The last line item of each order is supposed to be item "FEE", but occasionally order entry forgets to include it. I'm trying to find every instance where they failed to include the fee on the order.
So for the example data above, I would want to return order numbers 102 and 104 only.
Any ideas?
Just a guess since you don't specify what resultset you desire. And surely there is another table that you did not include that represents "orders" - perhaps named SALESORDERS?
Assuming that, then I suggest:
select ord."ORDER" -- a terrible idea to use reserved words as names
from dbo.SALESORDERS as ord
where not exists (select * from dbo.SALESORDERLINES as ordlines
where ord."ORDER" = ordlines."ORDER" and ordlines.ITEM = 'FEE')
order by ...;
Certainly there are other ways. EXCEPT comes to mind.
Try this :
SELECT ORDER
FROM TableA
WHERE ORDER NOT IN (
SELECT ORDER
FROM TableA
WHERE ITEM = 'FEE'
GROUP BY ORDER)
GROUP BY ORDER

Find Duplicates in a table

My table contains multiple lots (LOT_ID) and each lot contains multiple products(PRODUCT_ID) and there are multiple orders (ORDER_ID) under each Product. I would like to know the order ID’s which are repeated for multiple products for a given LOT
S.NO LOT_ID Product_ID Order_ID
1 101 P108 90001
2 101 P109 90001
3 101 P110 80900
4 102 S189 10098
5 102 S234 10087
6 102 S465 10098
7 102 S342 10050
8 103 L109 20090
9 103 L110 20098
10 103 L111 20020
Desired result
S.NO LOT_ID Product_ID Order_ID
1 101 P108 90001
2 101 P109 90001
3 102 S189 10098
4 102 S465 10098
I think you should apply group by on order_id first and you will get the result set. Please check the answer posted, However I haven't run this.
select LOT_ID, Product_ID, Order_ID
from <tableName>
where Order_ID IN (SELECT Order_ID FROM <tableName> where LOT_ID in (101,102)
GROUP BY Order_ID HAVING COUNT(*) > 1);
count repeats and then select the quantity you need
select t.*, count(*) over (partition by t.LOT_ID, t.Product_ID, t.Order_ID) as c
, count(*) over (partition by t.LOT_ID, t.Order_ID) as c2
from t
When count of unique strings is not equal count of unique Lots and Orders - is your case.

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, '') = ''

Last Invoice using Postgres

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

Getting a count while accounting for an attribute

I have two tables, one for account information and one for customer information. An account can have multiple customers associated with it. What I want to do is grab all active customers in a given month. However, I also want to account for customers who are active and purchased in earlier months.
Account
ID IND_ID LAST_PURCHASE
1 101 2013-01-15
2 102 2013-03-20
2 103 2013-02-05
3 104 2013-07-25
4 105 2012-01-11
Customer
ID STATUS
101 A
102 A
103 A
104 E
105 A
Select just the active customers is not the issue as I can just filter on that column. However, how can I select the count of active 'customers' while accounting for people who purchased in the past two month.
You can do this by looking at the maximum purchase date and filtering on that:
select c.id
from customer c join
account a
on c.id = a.ind_id
where c.status = 'A'
group by c.id
having max(last_purchase) >= date_add(month, -2, getdate());