SQL using result from select from clause to join another table - sql

I am working on a legacy app, I am still learning SQL and would consider my SQL knowledge as beginner.
I have 2 tables, one is a receipt type structure containing receipt no, a docket number (plus other info regarding total etc) and a car rego number.
there are the potential for multiple receipts for a car ie multiple matches on rego number
The second has a listing of the items related to that receipt (description, partno, time) each of the items are related by docketnumber - the "registerhistory"
multiple items appear as multiple rows (with same docketnumber) in the "registerhistory" and also items of the same type are not stored as a qty but as duplicated rows in the table with the same docket number each have a price stored
I am trying to generate a report based upon a search match on rego number and create a join to the matching tableregister items and list them (with hopefully an end goal of grouping any duplicate items into a qty and subtotal)
This is an access database if that changes the syntax
I am unclear on how I can take the results of one select query and use these results to create a join or there might be a better approach
So I need to firstly locate all receipts with a matching rego number, with those receipts, find the associated items (by docket number) hopefully group the items like so
receipt no 1
Item1 with multiples as qty with subtotal
Item2
Item3
receipt no 2
Item1
Item2 with multiples as qty with subtotal
Item3
Any help greatly appreciated,
(SELECT * from tblreceipts
where vehicle = 'abc123')
join tblregisterhistory on
tblreceipts.docketnum = tblregisterhistory.docketnum
I can even get to linking the results from the select query to a join, let alone get to my desired end result.

Are you trying to simply do a JOIN and GROUP BY? Something like this:
select partno, count(*) as qty
from tblreceipts as r inner join
tblregisterhistory as rh
on rh.docketnum = r.docketnum
where r.vehicle = 'abc123'
group by partno;

Ok with a bit of study and some helpful hints above. I have this (also apologies for the code formatting, still familiarising myself with the stack posting techniques)
SELECT vehicle, tblregisterhistory.date, partnumber, count(partnumber) as qty,
description, sum(price) as subtotal
FROM TBLRECEIPTS INNER JOIN
tblregisterhistory ON tblreceipts.docketnumber =
tblregisterhistory.docketnumber where tblreceipts.vehicle = 'abc123' group by
tblregisterhistory.date, vehicle, partnumber, description, price

Related

What's the use of this WHERE clause

this is an answer to the question : We need a list of customer IDs with the total amount they have ordered. Write a SQL statement to return customer ID (cust_id in the Orders table) and total_ordered using a subquery to return the total of orders for each customer. Sort the results by amount spent from greatest to the least. Hint: you’ve used the SUM() to calculate order totals previously.
SELECT prod_name,
(SELECT Sum(quantity)
FROM OrderItems
WHERE Products.prod_id=OrderItems.prod_id) AS quant_sold
FROM Products
;
So there is this simple code up here, and I know that this WHERE clause is comparing two columns in two different tables. But since We are calculating the SUM of that quantity, why do need that WHERE clause exactly. I really couldn't get it. Why the product_id exactly and not any other column ( p.s: the only shared column between those two tables is prod_id column ) I am still a beginner. Thank you!
First you would want to know the sum for each product - so need to adjust the subquery similar to this:
(SELECT prod_id, Sum(quantity) qty
FROM OrderItems
group by prod_id
) AS quant_sold
then once you know how much for each product, then you can link that
SELECT prod_name,
(SELECT prod_id, Sum(quantity) qty
FROM OrderItems
group by prod_id
) AS quant_sold
FROM Products p
WHERE p.prod_id = quant_sold.prod_id
Run it without the where clause and compare the results. You'll learn a lot that way. specifically focus on two different product Ids ensuring they both have order items and quantities.
You have two different tables involved. There are multiple products. You don't want the sum of all orders on each product; which is what you would get without the where clause. So the where clause correlates the two tables ensuring you only SUM the quantity of each order item for each product between the tables. Personally, I'd use a join, sum, and a group by as I find it easier to read and I'm not a fan of sub selects in the select of another query; but that's me.
SELECT prod_name,
(SELECT Sum(quantity)
FROM OrderItems
WHERE Products.prod_id=OrderItems.prod_id) AS quant_sold
FROM Products
Should be the same as:
SELECT prod_name, Sum(coalesce(P.quantity,0))
FROM Products P
LEFT JOIN orderItems OI
on P.prod_id=OI.prod_id
GROUP BY Prod_Name
'Notes
the above is untested.
a left join is needed because all products should be listed and if a product doesn't have an order, the quantity would be zero.
if we use an inner join, the product would be excluded.
We use coalesce because you'd have a "Null" quantity instead of zero for such lines without an order item.
as to which is "right" well it depends and varies on different cases. each has it's own merits and in different cases, one will perform better than another, and in a different case, vice-versa. See --> Join vs. sub-query
As an example:
Say you have Products A & B
"A" has Order Item Quantities of 1 & 2
"B" has order item Quantities of 10 & 20
If we don't have the where clause every result record would have qty 33
If we have the where product "A" would have 3
product "B" would have qty 30.

Trouble writing recursive query

I apologize for how potentially cluttered the explanation to my problem might be. I've
included details so that things make as much sense as possible leading up to the main
obstacle I've come across.
I'm working within Teradata using two tables that look like the following
Table Name Fields
Sales (ID, Sales)
Discounts (ID, PromoNum, Discount)
The PromoNum field consists of 9 digit unique promotion numbers which correspond to coupons.
This helps track whenever a transaction includes a specific coupon that was used. Each
transaction can have more than 1 coupon applied.
I'm trying to create a recursive query which pulls sales and discounts for a given set of coupons
in an iterative manner. The reason I'm doing so iteratively is because it is possible that a
single transaction can have more than 1 coupon applied (for 1 or more items). If I was avoid the
recursive query route and do an inner join on ID for example, it is possible that I could duplicate
records unnecessarily where two or more promo numbers were used within the same transaction, resulting
in potentially greater sales or discounts than actual. On top of this, I only have read access
to the database.
I've created a temp table called Promos with 3 specific promotions that I want to run interatively
and has the fields PromoNum and PromoIndex. PromoIndex is essentially the row number for each
promotion which I attempt to utilize in an interative manner below.
The recursive query I've writtens so far is as below. It doesn't work as expected due to the logic
behind the line I've commented. I need to rewrite this portion to make sure it simply runs for
the promotion number corresponding to the index at that specific iteration. For instance, when it
is at iteration 2, it will technically join on PromoIndex 1 and PromoIndex 2 when it should only run
for PromoIndex 2 if that makes sense. I've attempted to rewrite it while remaining within what's
allowed in a recursive query and I can't figure it out.
WITH RECURSIVE PromoData AS
(
SELECT
1 AS PromoIndex
, 1 AS PromoNum --dummy column
, 0 AS Sales --dummy column
, 0 AS Discounts --dummy column
FROM
Dummy Table
UNION ALL
SELECT
PromoData.PromoIndex + 1
, PromoData.PromoNum
, Sales.Sales
, Discounts.Discounts --Edited here
FROM Sales
INNER JOIN Discounts on Sales.ID = Discounts.ID
INNER JOIN Promos on Promos.PromoNum = Discounts.PromoNum and Promos.PromoIndex = PromoData.PromoIndex --Problematic portion here
WHERE PromoData.PromoIndex <= 3
)
SELECT *
FROM PromoData
From what you describe, you want:
select s.*
from sales s
where exists (select 1
from discounts d join
promos p
on d.promonum = p.promonum
where d.id = s.id
);
I don't see what a recursive query has to do with the problem you have described.
Recursive queries are normally used to resolve multiple layers of hierarchical rows, like those with a parent / child relationship. I don't think that is needed in this case.
The main issue I see here is you're trying to relate sales and discounts, but I don't see a natural way to do that. For example, if a transaction has $100 of sales and two discounts of $10 and $20 how much of the $100 gets attributed to each discount? I think this is what you meant by "two or more promo numbers being used within the same transaction" causing inflated figures.
Assuming your ID field is used as a transaction_ID, you can try something like:
WITH coupons AS (
SELECT 'PromoID1' AS PromoNum UNION ALL
SELECT 'PromoID2' AS PromoNum UNION ALL
SELECT 'PromoID3' AS PromoNum
)
SELECT
c.PromoNum,
COALESCE(info.sales, 0) sales,
COALESCE(info.discounts, 0) discounts
FROM coupons c -- get all specified coupons
LEFT JOIN (
SELECT
MAX(s.sales) sales,
SUM(d.discount) discounts, -- Get total discount for txn
MAX(d.PromoNum) AS PromoNum -- Pick a single PromoNum
FROM sales s -- Get all sales
LEFT JOIN discounts d ON s.ID = d.ID -- Get any discounts applied to sales
GROUP BY s.ID -- One row per txn (avoid double counting sales)
) info ON c.PromoNum = info.PromoNum -- Get related sales / discounts per PromoNum
The difference here is that in the case of a transaction with multiple discounts, all of the sales for that transaction will only be associated with a single PromoNum. This way you won't get inflated sales numbers.
Not sure if that's what you're after, but hope that helps.

Querying records that meet muliple criteria

Hi I’m trying to write a query and I’m struggling to figure out how to go about it.
I have a suppliers table and a supplier parts table I want to write a query that lists suppliers that have specified related Parts in the supplier parts table. If a supplier doesn’t have all specified related parts then they should not be listed.
At the moment I have written a very basic query that lists the supplier if they have a related supplier part that meets the criteria.
SELECT id ,name
FROM
efacdb.dbo.suppliers INNER JOIN [efacdb].[dbo].[spmatrix] ON
id = spmsupp
WHERE spmpart
IN ('ALUM_5083', 'ALUM_6082')
I only want to show the supplier if they have both parts related. Does anyone know how I could do this?
Use a subquery with counting distinct occurences:
select * from suppliers s
where 2 = (select count(distinct spmpart) from spmatrix
where id = spmsupp and spmpart in ('ALUM_5083', 'ALUM_6082'))
As a note, you can modify your query to get what you want, just by using an aggregation:
SELECT id, name
FROM efacdb.dbo.suppliers INNER JOIN
[efacdb].[dbo].[spmatrix]
ON id = spmsupp
WHERE spmpart IN ('ALUM_5083', 'ALUM_6082')
GROUP BY id, name
HAVING MIN(spmpart) <> MAX(spmpart);
If you know there are no duplicates, then having count(*) = 2 also solves the problem.

Access query/SQL - duplicates in one field with distinct multiple 2nd field

I am working on a database with products and lot numbers. Each entry in the Lots table has a Lot Number and a Product description.
Sometimes there are multiple records of the same lot number, for example when an item is repacked a new record is created, but with the same Lot Number and same product description - this is fine. But other times there are problem cases, namely when two different products share the same Lot Number. I am trying to find those.
In other words, there are 3 possibilities:
Lot numbers for which there is only one record in the table.
Lot numbers for which there are multiple records, but the Product description is the same for all of them
Lot numbers for which there are multiple records, and the product descriptions are not all the same.
I need to return only #3, with a separate record for each instance of that Lot Number and product description.
Any help would be greatly appreciated.
Thanks Juan for the sample data. Using this example, I want to return the data contained in Id 2-8, but not 1, 9, 10, 11.
This wasn't easy because lot of time don't use access.
First select unique values using distinct.
Then count how many diferent product appear on each lotnumber using group by
Last join both result and show only the lots with more than one description where total >1
.
SELECT id, Product.lotnumber, Product.Product, total
FROM
Product Inner join
(
SELECT lotnumber, count(*) as total
FROM
(SELECT distinct lotnumber, product
FROM Product)
GROUP BY lotnumber
) SubT On Product.lotnumber = SubT.lotnumber
WHERE total > 1
ORDER BY id
As you can see :
lot 2 have two products (yy and zz)
lot 3 have thre products (aa, bb, cc)
I include my product table:
Sorry for spanish. Field types are Autonumeric, Short Text, and Number

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?