Joining and aggregating data from multiple tables - sql

In customer table there is a SupportID which is the WorkerId in the worker Table, each WorkerId shows which will handle that customer.
Working Name | No. of accounts | total revenue
----------------------------------------------
John McCoy 20 10,000
Worker table contains - Firstname, Lastname, EmployeeId
Receipt table contains - receipt Id, CustomerId,
ReceiptLine Table contains - receiptlineId, receipt Id, Unitprice, quantity
At the moment I have this code / idea
SELECT FirstName, LastName
FROM Employee A, Invoice B
WHERE A.EmployeeId = B.CustomerId

In this question, you have not mention dependency among worker and receipt table. However, let the dependency column is workerId on table receipt. Now try this, hope you will get your desired result.
select a.firstName, sum(count(b.customerId)) as no_accounts, sum(c.unitPrice *c.quantity) as total_revenue
from (( worker a join receipt b on a.workerId = b.SupportId)
join receiptLine c on b.receiptId = c.receiptId) group by a.firstName order by a.firstName;

use GROUP BY to resolve your problem

Related

Two group by tables stich another table

I have 3 tables I need to put together.
The first table is my main transaction table where I need to get distinct transaction id numbers and company id. It has all the important keys. The transaction ids are not unique.
The second table has item info which is linked to transaction id numbers which are not unique and I need to pull items.
The third table has company info which has company id.
Now I've sold some of these with the first one through a group by id. The second through a subquery which creates unique ids and joins onto the first one.
The issue I'm having is the third one by company. I cannot seem to create a query that works in the above combinations. Any ideas?
As suggested here is my code. It works but that's because for the company I used count which doesn't give the correct number. How else can I get the company number to come out correct?
SELECT
dep.ItemIDAPK,
dep.TotalOne,
dep.company,
company.vendname,
appd.ItemIDAPK,
appd.ItemName
FROM (
SELECT
csi.ItemIDAPK,
sum(f.TotalOne) as TotalOne,
count(f.DimCurrentcompanyID) company
FROM dbo.ReportOne F with (nolock)
INNER JOIN dbo.DSaleItem csi with (nolock)
on f.DSaleItemID = csi.DSaleItemID
INNER JOIN dbo.DimCurrentcompany cv
ON f.DimCurrentcompanyID = cv.DimCurrentcompanyID
INNER JOIN dbo.DimDate dat
on f.DimDateID = dat.DimDateID
where (
dat.date >='2013-01-29 00:00:00.000'
and dat.date <= '2013-01-30 00:00:00.000'
)
GROUP BY csi.ItemIDAPK
) as dep
INNER JOIN (
SELECT
vend.DimCurrentcompanyID,
vend.Name vendname
FROM dbo.DimCurrentcompany vend
) As company
on dep.company = company.DimCurrentcompanyID
INNER JOIN (
SELECT
c2.ItemIDAPK,
ItemName
FROM (
SELECT DISTINCT ItemIDAPK
FROM dbo.dimitem AS C
) AS c1
JOIN dbo.dimitem AS c2 ON c1.ItemIDAPK = c2.ItemIDAPK
) as appd
ON dep.ItemIDAPK = appd.ItemIDAPK
For further information my output is the following example, I know the code executes and the companyid is incorrect as I just put it with a (count) in their to make the above code execute:
Current Results:
Item Number TLS CompanyID Company Name Item Number Item Name
111111 300 303 Johnson Corp 29323 Soap
Proposed Results:
Item Number TLS CompanyID Company Name Item Number Item Name
111111 300 29 Johnson Corp 29323 Soap

SQL Join two tables using versioned data

I have two tables, both of which have a record date as part of the key. When the record is edited, a new version of it with the current RecordDate and whatever other changes were made is created. This applies to both tables. The RecordDate is not used as a foreign key at all only applies to its own table.
So for this example, Kate gets married, her employee record is updated to reflect her new surname. She is also taken off the fish counter and given a cushy job in management and so her Employee Task also changes.
Employee
CompanyId EmployeeId RecordDate Name
1 1 2011/04/11 Kate Windsor
1 1 2010/07/04 Kate Middleton
EmployeeTasks
CompanyId EmployeeId RecordDate TaskId TaskCode
1 1 2015/09/18 1 bbb
1 1 2015/09/18 1 aaa
I can select the most recent set of records for a single table, I can join one of these tables with another non versioned table but what I cannot figure out how to do is to join both these tables together such that I get data for the most recent records for each, so that it would return something like this?
CompanyId EmployeeId Name TaskId TaskCode
1 1 Kate Windsor 1 bbb
FWIW Im using an Oracle DB.
It's a bit messy, but you need to get down to just the employee and company IDs with a max record date for each. With the MAX date from each table those can be used to join back to the base tables and pull only the related records.
SELECT e.companyID, e.employeeID,
FROM (SELECT companyID, employeeID, MAX(RecordDate) AS maxDate
FROM employee
GROUP BY companyID, employeeID
) e
INNER JOIN (SELECT companyID, employeeID, MAX(RecordDate) AS maxDate
FROM employeeTasks
GROUP BY companyID, employeeID
) et ON e.companyID = et.companyID AND e.employeeID = et.employeeID
INNER JOIN employee emp
ON e.companyID = emp.companyID AND e.employeeID = emp.employeeID AND emp.RecordDate = e.maxDate
INNER JOIN employeeTask oN empT
ON et.companyID = empT.companyID AND et.employeeID = empT.employeeID AND empT.RecordDate = et.maxDate
Sorry for the initial, incomplete post, my fingers got away from me and accidentally submitted too soon!

Select all customers loyal to one company?

I've got tables:
TABLE | COLUMNS
----------+----------------------------------
CUSTOMER | C_ID, C_NAME, C_ADDRESS
SHOP | S_ID, S_NAME, S_ADDRESS, S_COMPANY
ORDER | S_ID, C_ID, O_DATE
I want to select id of all customers who made order only from shops of one company - 'Samsung' ('LG', 'HP', ... doesn't really matter, it's dynamic).
I've come only with one solution, but I consider it ugly:
( SELECT DISTINCT c_id FROM order JOIN shop USING(s_id) WHERE s_company = "Samsung" )
EXCEPT
( SELECT DISTINCT c_id FROM order JOIN shop USING(s_id) WHERE s_company != "Samsung" );
Same SQL queries, but reversed operator. Isn't there any aggregate method which solves such query better?
I mean, there could be millions of orders(I don't really have orders, I've got something that occurs more often).
Is it efficient to select thousands of orders and then compare them to hundreds of thousands orders which have different company? I know, that it compares sorted things, so it's O( m + n + sort(n) + sort(m) ). But that's still large for millions of records, or isn't?
And one more question. How could I select all customer values (name, address). How can I join them, can I do just
SELECT CUSTOMER.* FROM CUSTOMER JOIN ( (SELECT...) EXCEPT (SELECT...) ) USING (C_ID);
Disclaimer: This question ain't homework. It's preparation for the exam and desire to things more effective. My solution would be accepted at exam, but I like effective programming.
I like to approach this type of question using group by and a having clause. You can get the list of customers using:
select o.c_id
from orders o join
shops s
on o.s_id = o.s_id
group by c_id
having min(s.s_company) = max(s.s_company);
If you care about the particular company, then:
having min(s.s_company) = max(s.s_company) and
max(s.s_company) = 'Samsung'
If you want full customer information, you can join the customers table back in.
Whether this works better than the except version is something that would have to be tested on your system.
How about a query that uses no aggregate functions like Min and Max?
select C_ID, S_ID
from shop
group by C_ID, S_ID;
Now we have a distinct list of customers and all the companies they shopped at. The loyal customers will be the ones who only appear once in the list.
select C_ID
from Q1
group by C_ID
having count(*) = 1;
Join back to the first query to get the company id:
with
Q1 as(
select C_ID, S_ID
from shop
group by C_ID, S_ID
),
Q2 as(
select C_ID
from Q1
group by C_ID
having count(*) = 1
)
select Q1.C_ID, Q1.S_ID
from Q1
join Q2
on Q2.C_ID = Q1.C_ID;
Now you have a list of loyal customers and the one company each is loyal to.

How to get distinct and lastest record with inner join query

I have two table named: customers and bill. customer and bill have one to many relation.
Customer table contains record of customer mobileNo,bikeNo etc
Bill table contain record of customer bill with bikeNo(foreign key),billdate etc.
I have query for that:
SELECT customer.mobileNo, bill.iDate AS Expr1
FROM (customer INNER JOIN
bill ON customer.bikeNo = bill.bikeNo)
ORDER BY bill.iDate;
Now How i get distinct and latest billdate record and mobileNo with this query?
Use GROUP BY and MAX():
SELECT customer.mobileNo, MAX(bill.iDate) AS iDate
FROM (customer INNER JOIN
bill ON customer.bikeNo = bill.bikeNo)
GROUP BY customer.mobileNo
ORDER BY iDate

SQL Retrieval question

I am trying to retrieve the following information:
For each customer whose average order amount is greater than $1,800, list the customer name, cust# and total number of orders.
my code is currently.
SELECT c.cname, c.`cust#`, COUNT(oi.`order#`)
FROM CUSTOMER c, `ORDER` o, `ORDER_ITEM` oi
WHERE c.`cust#` = o.`cust#`
AND o.`order#` = oi.`order#`
AND AVG(o.`ord_amt`) > 1800
GROUP BY c.cname, c .`cust#`
THE TABLES AND FIELDS TO MY DATABASE
customer(cust#:char(3), cname:varchar(30), city:varchar(20))
order (order# :char(4), odate, cust#:char(3), ord_amt:decimal(10.2))
order_item( order# :char(4), item#: char(4), qty:int(11))
item(item# :char(4), unit_price:decimal(10.2))
shipment(order# :char(4), warehouse# :char(4), ship_date:date)
warehouse (warehouse#: char(4), city:varchar(20))
You should use JOIN notation and a HAVING clause to compare the aggregate; you don't need the order items table:
SELECT c.cname, c.`cust#`, COUNT(oi.`order#`)
FROM CUSTOMER c JOIN `ORDER` o ON c.`cust#` = o.`cust#`
GROUP BY c.cname, c .`cust#`
HAVING AVG(o.`ord_amt`) > 1800
(Order of GROUP BY and HAVING fixed per comment by GolezTrol - thanks; my excuse is that it was late at night.)