SQL query from an existing list - sql

Sql newb so im trying to figure this out:
I pull a list of customer names that purchase a certain item:
select r.name
from records r
where r.item_purchased='apple'
Now I want to take that list of customers and pull the records for everything they have purchased, but I can't get past the errors. I've tried things like:
with customer_list as
(above)
select r.*
from records r
where r.name=customer_list

If you do want to use a CTE, this should work:
with customer_list as
(
select r.name
from records r
where r.item_purchased='apple'
)
select r.*
from records r
where r.name in (select name from customer_list)
The difference between this and a JOIN (e.g. Michael's solution) is the join will produce a different result if the same customer purchased an apple more than once.

I believe a self join should solve your problem:
select distinct r2.*
from records r
join records r2
on r2.name = r.name
where r.item_purchased='apple'
EDIT: Added a DISTINCT based on #a_horse_with_no_name's insight into the difference between the results, because I doubt the duplication caused by the self join would be the desired result.

Select * from records where name in (
select name
from records
where item_purchased='apple'
)

Related

How to fetch distinct records from SQL Server Compact database

How do I get unique records from multiple tables using SQL Server Compact?
I tried with this SQL statement:
SELECT Tbl_Customer.Name, Tbl_Room.Room_Number
FROM Tbl_Customer
INNER JOIN Tbl_Room ON Tbl_Customer.Customer_number = Tbl_Room.Customer_Number
WHERE Tbl_Customer.Customer_number IN (SELECT DISTINCT Tbl_Customer.Customer_number
FROM Tbl_Customer)
I don't understand why there is this WHERE statement. You are trying to get records from Tbl_Customer that have Customer_number existing in the same table - Tbl_Customer. Without this condition, you can use
SELECT c.Name, r.Room_Number
FROM Tbl_Customer c
INNER JOIN Tbl_Room r ON c.Customer_number = r.Customer_Number
GROUP BY c.Name, r.Room_Number
I hope it helps.
EDIT: In this case SELECT DISTINCT should give the same results and even generate exactly the same query execution plan.

Adding more tables to an SQL query with a Union

I am taking 2 columns (PaidGross and PaidDiscount) and putting them in a single column (Amount) for my results. (I am not trying to concatenate. My result will have ALL records from both columns in a single column)
The basic query is this:
SELECT PaidGross AS Amount, BillingID FROM APPaidInvDtl(noLock)
UNION ALL
SELECT PaidDiscount AS Amount, BillingID FROM APPaidInvDtl(noLock)
It returns 35706 records and seems to be getting what I want so I think I have that part figured out but...
Here is my expanded query as I am trying to include data from other tables as well:
SELECT APPaidInvDtl.PaidGross AS Amount, APPaidInvDtl.BillingID, DocumentLinks.DocIDInternal, DocumentLinks.LinkDocIDInternal
FROM APPaidInvDtl
INNER JOIN DocumentLinks ON APPaidInvDtl.BillingID=DocumentLinks.DocIDInternal
UNION ALL
SELECT APPaidInvDtl.PaidDiscount AS Amount, APPaidInvDtl.BillingID, DocumentLinks.DocIDInternal, DocumentLinks.LinkDocIDInternal
FROM APPaidInvDtl
INNER JOIN DocumentLinks ON APPaidInvDtl.BillingID=DocumentLinks.DocIDInternal
I get 102408 records with my expanded query so obviously I am doing something wrong. I believe I need to get exactly the same number of records in both queries to know that I'm getting the right data.
Thank you for any help or ideas on what I should try! Jordan
Update on March 16, 2018:
#Smog #shwant00 Yes, you are right. There are multiple documents linked so I am trying restrict it to a certain type of document. The links between the documents are stored in the DocumentLinks table however the Documents table is the one that has the types of documents specified. So I'm having trouble getting the right data at the right time. My latest try gives me the error: "DocumentLinks.LinkDocIDInternal" could not be bound." Here is my latest try:
SELECT APPaidInvDtl.PaidGross AS Amount, APPaidInvDtl.BillingID, Invoice.DocIDInternal, Invoice.DocYYMM, Invoice.Docseq, Checkrun.DocIDInternal, Checkrun.DocYYMM, Checkrun.Docseq, DocumentLinks.DocIDInternal, DocumentLinks.LinkDocIDInternal
FROM APPaidInvDtl(nolock)
INNER JOIN Documents Invoice ON APPaidInvDtl.BillingID=Invoice.DocIDInternal
INNER JOIN Documents Checkrun ON DocumentLinks.LinkDocIDInternal=Checkrun.DocIDInternal
INNER JOIN DocumentLinks ON APPaidInvDtl.BillingID=DocumentLinks.DocIDInternal WHERE Checkrun.Doctype=27
UNION ALL
SELECT APPaidInvDtl.PaidDiscount AS Amount, APPaidInvDtl.BillingID, Invoice.DocIDInternal, Invoice.DocYYMM, Invoice.Docseq, Checkrun.DocIDInternal, Checkrun.DocYYMM, Checkrun.Docseq, DocumentLinks.DocIDInternal, DocumentLinks.LinkDocIDInternal
FROM APPaidInvDtl(nolock)
INNER JOIN Documents Invoice ON APPaidInvDtl.BillingID=Invoice.DocIDInternal
INNER JOIN Documents Checkrun ON DocumentLinks.LinkDocIDInternal=Checkrun.DocIDInternal
INNER JOIN DocumentLinks ON APPaidInvDtl.BillingID=DocumentLinks.DocIDInternal WHERE Checkrun.Doctype=27
How about this?
with #tmp as (
SELECT PaidGross AS Amount, BillingID as BillingID FROM APPaidInvDtl(noLock)
UNION ALL
SELECT PaidDiscount AS Amount, BillingID as BillingID FROM
APPaidInvDtl(noLock)
)
select t.Amount, t.BillingID, d.DocIDInternal, d.LinkDocInternal
from #tmp t
inner join DocumnetLinks d on d.BillingID = t.BillingID
I would guess that if you run the first select in the union you will get 51204 rows. The increase from 35706 is caused by the join, but the increase from 51204 to 102408 is because you are using union all. Union all don’t filter out duplicate rows. You need to use union only wich will filter out duplicate rows and only returns distinct rows.

SQL Server 2016 Sub Query Guidance

I am currently working on an assignment for my SQL class and I am stuck. I'm not looking for full code to answer the question, just a little nudge in the right direction. If you do provide full code would you mind a small explanation as to why you did it that way (so I can actually learn something.)
Here is the question:
Write a SELECT statement that returns three columns: EmailAddress, ShipmentId, and the order total for each Client. To do this, you can group the result set by the EmailAddress and ShipmentId columns. In addition, you must calculate the order total from the columns in the ShipItems table.
Write a second SELECT statement that uses the first SELECT statement in its FROM clause. The main query should return two columns: the Client’s email address and the largest order for that Client. To do this, you can group the result set by the EmailAddress column.
I am confused on how to pull in the EmailAddress column from the Clients table, as in order to join it I have to bring in other tables that aren't being used. I am assuming there is an easier way to do this using sub Queries as that is what we are working on at the time.
Think of SQL as working with sets of data as opposed to just tables. Tables are merely a set of data. So when you view data this way you immediately see that the query below returns a set of data consisting of the entirety of another set, being a table:
SELECT * FROM MyTable1
Now, if you were to only get the first two columns from MyTable1 you would return a different set that consisted only of columns 1 and 2:
SELECT col1, col2 FROM MyTable1
Now you can treat this second set, a subset of data as a "table" as well and query it like this:
SELECT
*
FROM (
SELECT
col1,
col2
FROM
MyTable1
)
This will return all the columns from the two columns provided in the inner set.
So, your inner query, which I won't write for you since you appear to be a student, and that wouldn't be right for me to give you the entire answer, would be a query consisting of a GROUP BY clause and a SUM of the order value field. But the key thing you need to understand is this set thinking: you can just wrap the ENTIRE query inside brackets and treat it as a table the way I have done above. Hopefully this helps.
You need a subquery, like this:
select emailaddress, max(OrderTotal) as MaxOrder
from
( -- Open the subquery
select Cl.emailaddress,
Sh.ShipmentID,
sum(SI.Value) as OrderTotal -- Use the line item value column in here
from Client Cl -- First table
inner join Shipments Sh -- Join the shipments
on Sh.ClientID = Cl.ClientID
inner join ShipItem SI -- Now the items
on SI.ShipmentID = Sh.ShipmentID
group by C1.emailaddress, Sh.ShipmentID -- here's your grouping for the sum() aggregation
) -- Close subquery
group by emailaddress -- group for the max()
For the first query you can join the Clients to Shipments (on ClientId).
And Shipments to the ShipItems table (on ShipmentId).
Then group the results, and count or sum the total you need.
Using aliases for the tables is usefull, certainly when you select fields from the joined tables that have the same column name.
select
c.EmailAddress,
i.ShipmentId,
SUM((i.ShipItemPrice - i.ShipItemDiscountAmount) * i.Quantity) as TotalPriceDiscounted
from ShipItems i
join Shipments s on (s.ShipmentId = i.ShipmentId)
left join Clients c on (c.ClientId = s.ClientId)
group by i.ShipmentId, c.EmailAddress
order by i.ShipmentId, c.EmailAddress;
Using that grouped query in a subquery, you can get the Maximum total per EmailAddress.
select EmailAddress,
-- max(TotalShipItems) as MaxTotalShipItems,
max(TotalPriceDiscounted) as MaxTotalPriceDiscounted
from (
select
c.EmailAddress,
-- i.ShipmentId,
-- count(*) as TotalShipItems,
SUM((i.ShipItemPrice - i.ShipItemDiscountAmount) * i.Quantity) as TotalPriceDiscounted
from ShipItems i
join Shipments s on (s.ShipmentId = i.ShipmentId)
left join Clients c on (c.ClientId = s.ClientId)
group by i.ShipmentId, c.EmailAddress
) q
group by EmailAddress
order by EmailAddress
Note that an ORDER BY is mostly meaningless inside a subquery if you don't use TOP.

Oracle - select statement to rollup multiple tables within a time frame

I have 3 Oracle tables for a project that link a demo Transaction table to Transaction_Customer and Transaction_Employee as shown below. Each transaction can have multiple customers involved and many employees involved.
I am trying to write a SQL query which will list each Customer_ID that has had transactions with multiple employees within a one period. I would like the output to include a single row for each Customer_ID with a comma separated list of which Employee_IDs had a transaction with that customer.
The output should look like this:
Customer_ID|Employees
601|007,008,009
The basic query to join the tables together looks like this:
select * from transactions t
left join transactions_customer tc
on t.t_id = tc.t_id
left join transactions_employee te
on t.t_id = te.t_id
How do I get this do I finish this assignment and get the query working the way intended?
Thank you!
Transactions
T_ID|Date|Amount
1|1/10/2017|100
2|1/10/2017|200
3|1/31/2017|150
4|2/16/2017|175
5|2/17/2017|175
6|2/18/2017|185
Transactions_Customer
T_ID|Customer_ID
1|600
1|601
1|602
2|605
3|606
4|601
5|607
6|607
Transactions_Employee
T_ID|Employee_ID
1|007
1|008
2|009
3|008
4|009
5|007
6|007
Is this what you want?
select tc.Customer_id,
listagg(te.employee_id, ',') within group (order by te.employee_id) as employees
from Transactions_Customer tc join
Transactions_Employee te
on tc.t_id = te.t_id
group by tc.Customer_id;
You only need the Transactions table for filtering on the date. Your question alludes to such filtering but does not exactly describe it, so I left it out.
Edit:
The customer data (and perhaps the employees data too) has duplicates. To avoid these in the output:
select tc.Customer_id,
listagg(te.employee_id, ',') within group (order by te.employee_id) as employees
from (select distinct tc.t_id, tc.customer_id
from Transactions_Customer tc
) tc join
(select distinct te.t_id, te.employee_id
from Transactions_Employee te
) te
on tc.t_id = te.t_id
group by tc.Customer_id;

Update using Distinct SUM

I have found a few good resources that show I should be able to merge a select query with an update, but I just can't get my head around of the correct formatting.
I have a select statement that is getting info for me, and I want to pretty much use those results to Update an account table that matches the accountID in the select query.
Here is the select statement:
SELECT DISTINCT SUM(b.workers)*tt.mealTax as MealCost,b.townID,b.accountID
FROM buildings AS b
INNER JOIN town_tax AS tt ON tt.townID = b.townID
GROUP BY b.townID,b.accountID
So in short I want the above query to be merged with:
UPDATE accounts AS a
SET a.wealth = a.wealth - MealCost
Where MealCost is the result from the select query. I am sure there is a way to put this into one, I just haven't quite been able to connect the dots to get it to run consistently without separating into two queries.
First, you don't need the distinct when you have a group by.
Second, how do you intend to link the two results? The SELECT query is returning multiple rows per account (one for each town). Presumably, the accounts table has only one row. Let's say that you wanted the average MealCost for the update.
The select query to get this is:
SELECT accountID, avg(MealCost) as avg_Mealcost
FROM (SELECT SUM(b.workers)*tt.mealTax as MealCost, b.townID, b.accountID
FROM buildings AS b INNER JOIN
town_tax AS tt
ON tt.townID = b.townID
GROUP BY b.townID,b.accountID
) a
GROUP BY accountID
Now, to put this into an update, you can use syntax like the following:
UPDATE accounts
set accounts.wealth = accounts.wealth + asum.avg_mealcost
from (SELECT accountID, avg(MealCost) as avg_Mealcost
FROM (SELECT SUM(b.workers)*tt.mealTax as MealCost, b.townID, b.accountID
FROM buildings AS b INNER JOIN
town_tax AS tt
ON tt.townID = b.townID
GROUP BY b.townID,b.accountID
) a
GROUP BY accountID
) asum
where accounts.accountid = asum.accountid
This uses SQL Server syntax, which I believe is the same as for Oracle and most other databases. Mysql puts the "from" clause before the "set" and allows an alias on "update accounts".