How to get two fields based off a most recent date attribute? - sql

I have two tables:
A Billing table, and a Customer table.
The Billing table and customer table both share a common attribute of Customer Number.
Billing Table
I'm trying to create a view that will retrieve the customer code and bill number for the most recent invoice date. I'm having trouble ordering my query.
This is what I have so far.
CREATE VIEW RECENT_ORDER
AS
SELECT
c.Customer_Num, b.Bill_Num
FROM CUSTOMER c
INNER JOIN BILLING b ON c.Customer_Num = b.Customer_Num
WHERE c.Fname='Jess' AND c.Lname='Hanks'
HAVING MAX(b.Bill_Date);
I have also tried putting the 'HAVING' portion as a WHERE statement.

This should get your answer:
CREATE VIEW RECENT_ORDER
AS
SELECT c.customer_num, b.bill_num
FROM customer c
JOIN billing b ON c.customer_num = b.customer_num
WHERE b.bill_date =
(SELECT MAX(bill_date) FROM billing WHERE customer_num = b.customer_num)
AND c.Fname='Jess' AND c.Lname='Hanks'
Though normally I wouldn't expect to create a view that limits results to just one customer!? Remove the last line AND c.Fname ... if you intend to get the most recent result for any/all customers. Note that you may get multiple results for a customer if they have more than one invoice on the same date.

Related

Why do repeated values appear in SQL results

I'm with a doubt about joins. For example, using an example database dvdrental, this query:
SELECT customer.customer_id
, first_name
, last_name
FROM customer
INNER JOIN payment ON Customer.customer_id = Payment.customer_id
Some records appear repeated, for example, it appears 3 times "342 Harold Martino" like:
342 Harold Martino
342 Harold Martino
342 Harold Martino
Do you know why it appears repeated records like in this example that appears the same Record 3 times? This repetition means that there are 3 records in the payment table where customer_id = 342? But this query "select * from payment where customer_id = 342" returns 32 records. So I'm not understanding properly how the join works.
There are many resources around this, so to be short your expression says this in plain english:
Get all the records from the customer table
Then for each of those records, get every payment record that has the same value in the customer_Id field.
return a single row for each payment record that duplicates all the fields from the customer record for each row in the payment record.
Finally, only return 3 columns:
the customer_id column from the customer table
the first_name column that is in one of the customer or payment table
the last_name column that is in one of the customer or payment table
Note that we didn't bring back any columns from the payment table... (I assume first_name and last_name are fields in the customer table...)
Keep in mind, a CROSS JOIN (or a FULL OUTER JOIN) is a join that says take all fields from the left side and create a single row combination that is multiplied by the right side, so for every row on the left, return a combination of the left row with every row on the right. So the number of rows returned in a CROSS JOIN is the number of rows in the current table, multiplied by the number of rows in the joined table.
In your query, an INNER JOIN or LEFT INNER JOIN will produce a recordset that includes all the fields from the current table structure and will include fields from the joined table as well.
the implicit LEFT component specifies that only records that match the existing table structure should be returned, so in this case only Payment records that match a customer_id in the currently not filtered customer table will be returned.
The number of resulting rows is the number of rows in the joined table that have a match in the current table.
If instead you want to query:
Select all the customers that have payments
then you can use a join, but you should also use a DISTINCT clause, to only return the unique records:
SELECT DISTINCT customer.customer_id
, first_name
, last_name
FROM customer
INNER JOIN payment ON Customer.customer_id = Payment.customer_id
An alternative way to do this is to use a sub-query instead of a join:
SELECT customer_id
, first_name
, last_name
FROM customer
WHERE EXISTS (SELECT customer_id FROM payment WHERE payment.customer_id = customer.customer_id)
The rules on when to use one style of query over the other are pretty convoluted and very dependant on the number of rows in each table, the types of indexes that are available and even the type or version of the RDBMS you are operating within.
To optimise, run both queries, compare the results and timing and use the one that fits your database better. If later performance becomes an issue, try the other one :)
Select the Customer_id field

How to get customers that have not placed orders in a period of time using two different tables

I want a list of customers that have not placed an order in a certain date period on two different tables
I tried this:But is bring back nothing
SELECT "OEORDH"."CUSTOMER","OEORDH"."BILNAME","OEORDH"."ORDDATE"
FROM "SAMINC"."dbo"."OEORDH"
inner JOIN "SAMINC"."dbo"."ARCUS"on "ARCUS"."IDCUST" = "OEORDH"."CUSTOMER"
where "OEORDH"."ORDDATE" is null
ORDER BY "ARCUS"."IDCUST"
Please help
I expect the output to show me all customers that have not place orders.

Join table query returns multiple results from right table

I'm new to access and Have pulled tog ether a query in the GUI.
I have a Join set up so all customers who have complained are in the left table and all work completed is in the right table.
Both table have the customers reference number so I've joined based on that.
Customers may complain before we've carried out any work so the table is a left Join.
The problem I have is a customer may have had multiple work items, so when I create the join each row in the complaints table is being returned multiple times if they have had more than on work item carried out.
I need to add some logic to the joins so it only brings back a single work item for each complaint. Where multiple work items are present are want the query to return the work item with the date closets to the date of the complaint but never after it.
If the complaint has no work items that occur before it I still want the complain to be shown but with data from the work item.
I only really know how to use the designer GUI but the SQL looks like this at the moment:
SELECT DISTINCT [CEAR326 Master Data fo access1].ID,
ReportingCategory.ReportingCategory,
[CEAR326 Master Data fo access1].Category,
[CEAR326 Master Data fo access1].[Sub Category],
[CEAR326 Master Data fo access1].[Contact Partner],
main_Tbl_ServiceOrder.ServiceProduct, SOType.SOType,
Format([Actual Date From],"mmm-yy") AS [Date],
[CEAR326 Master Data fo access1].[Actual Date From],
main_Tbl_ServiceOrder.BasicStartDate,
[CEAR326 Master Data fo access1].Smart_Flag
FROM (([CEAR326 Master Data fo access1]
LEFT JOIN main_Tbl_ServiceOrder ON [CEAR326 Master Data fo access1].[Contact Partner] = main_Tbl_ServiceOrder.BusinessPartnerNumber)
LEFT JOIN ReportingCategory ON [CEAR326 Master Data fo access1].Category = ReportingCategory.Category) LEFT JOIN SOType ON main_Tbl_ServiceOrder.ServiceProduct = SOType.ServiceOrder
WHERE (((main_Tbl_ServiceOrder.BasicStartDate)<="actual Date from" Or (main_Tbl_ServiceOrder.BasicStartDate)="0" Or (main_Tbl_ServiceOrder.BasicStartDate) Is Null))
ORDER BY [CEAR326 Master Data fo access1].[Contact Partner], main_Tbl_ServiceOrder.BasicStartDate;
I believe the Select distinct isn't working as required due to the line
main_Tbl_ServiceOrder.ServiceProduct, SOType.SOType,
This is where I want my where statement to come in and select the relevant service order by looking at the date of the service order in relation to the date of the CEAR [Actual Date From].
I also think there would be an issue with the current WHERE statement returning multiple Service orders if they occur before the CEAR. I'd only want to return the one closest to the CEAR date.
This uses
Complaints table with ComplaintID as the key and fields for Customer and Complaint_Date
WorkOrders table with WorkOrderID as they key and fields for Customer and WorkOrder_date
I assumed there is only one work order per customer per date. If this isn't true, you may need to use an autonumber field for the WorkOrders instead of the date field in the selection criteria
You should be able to customize this with your table names and field names.
SELECT Complaints.ComplaintID, Complaints.Customer, Complaints.Complaint_date, WorkOrders.WorkOrderID, WorkOrders.WorkOrder_date
FROM Complaints LEFT JOIN WorkOrders ON Complaints.Customer = WorkOrders.Customer
WHERE (((WorkOrders.WorkOrder_date) Is Null Or (WorkOrders.WorkOrder_date)=(select max(WorkOrder_Date) from WorkOrders T where T.customer=Complaints.customer and T.WorkOrder_date<Complaint_date)));

SQL, Select from table A and use result ID to loop though table B?

I have a windows server running MS-SQL 2008.
I have a customer table that I need to select the id's of all customers that are Active, On Hold, or Suspended.
get all customers that are Y= current active customer H=on hold S=Suspended
select id from customer where active = 'Y';
the above statement worked fine for selecting the ID's of the affected customers.
I need to use these results to loop though the following command in order to find out what rates all the affected customers have.
get all rates for a customer
select rgid from custrate where custid = [loop though changing this id with results from first statement];
the id from the customer table coincides with the custid from the custrate table.
So in the end I need a list of all affected customer id's and what rgid's(rate group(s)) they have.
SQL isn't about loops in general and instead you should think in terms of joins.
select customer.id, custrate.rgid, customer.active
from customer
inner join custrate
on customer.id = custrate.custid
where active in ('Y', 'H', 'S")
order by customer.active, customer.id
would be a starting point to think about. However, that is just a wild guess as the schema was not specified nor the relations between the tables.

Joining table issue with SQL Server 2008

I am using the following query to obtain some sales figures. The problem is that it is returning the wrong data.
I am joining together three tables tbl_orders tbl_orderitems tbl_payment. The tbl_orders table holds summary information, the tbl_orderitems holds the items ordered and the tbl_payment table holds payment information regarding the order. Multiple payments can be placed against each order.
I am trying to get the sum of the items sum(mon_orditems_pprice), and also the amount of items sold count(uid_orderitems).
When I run the following query against a specific order number, which I know has 1 order item. It returns a count of 2 and the sum of two items.
Item ProdTotal ProdCount
Westvale Climbing Frame 1198 2
This order has two payment records held in the tbl_payment table, which is causing the double count. If I remove the payment table join it reports the correct figures, or if I select an order which has a single payment it works as well. Am I missing something, I am tired!!??
SELECT
txt_orditems_pname,
SUM(mon_orditems_pprice) AS prodTotal,
COUNT(uid_orderitems) AS prodCount
FROM dbo.tbl_orders
INNER JOIN dbo.tbl_orderitems ON (dbo.tbl_orders.uid_orders = dbo.tbl_orderitems.uid_orditems_orderid)
INNER JOIN dbo.tbl_payment ON (dbo.tbl_orders.uid_orders = dbo.tbl_payment.uid_pay_orderid)
WHERE
uid_orditems_orderid = 61571
GROUP BY
dbo.tbl_orderitems.txt_orditems_pname
ORDER BY
dbo.tbl_orderitems.txt_orditems_pname
Any suggestions?
Thank you.
Drill down Table columns
dbo.tbl_payment.bit_pay_paid (1/0) Has this payment been paid, yes no
dbo.tbl_orders.bit_order_archive (1/0) Is this order archived, yes no
dbo.tbl_orders.uid_order_webid (integer) Web Shop's ID
dbo.tbl_orders.bit_order_preorder (1/0) Is this a pre-order, yes no
YEAR(dbo.tbl_orders.dte_order_stamp) (2012) Sales year
dbo.tbl_orders.txt_order_status (varchar) Is the order dispatched, awaiting delivery
dbo.tbl_orderitems.uid_orditems_pcatid (integer) Product category ID
It's a normal behavior, if you remove grouping clause you'll see that there really are 2 rows after joining and they both have 599 as a mon_orditems_pprice hence the SUM is correct. When there is a multiple match in any joined table the entire output row becomes multiple and the data that is being summed (or counted or aggregated in any other way) also gets summed multiple times. Try this:
SELECT txt_orditems_pname,
SUM(mon_orditems_pprice) AS prodTotal,
COUNT(uid_orderitems) AS prodCount
FROM dbo.tbl_orders
INNER JOIN dbo.tbl_orderitems ON (dbo.tbl_orders.uid_orders = dbo.tbl_orderitems.uid_orditems_orderid)
INNER JOIN
(
SELECT x.uid_pay_orderid
FROM dbo.tbl_payment x
GROUP BY x.uid_pay_orderid
) AS payments ON (dbo.tbl_orders.uid_orders = payments.uid_pay_orderid)
WHERE
uid_orditems_orderid = 61571
GROUP BY
dbo.tbl_orderitems.txt_orditems_pname
ORDER BY
dbo.tbl_orderitems.txt_orditems_pname
I don't know what data from tbl_payment you are using, are any of the columns from the SELECT list actually from tbl_payment? Why is tbl_payment being joined?