Creating a table view for invoice - Northwind - sql

I have a little problem with my last tasks. I am using an old Northwind database.
First, I had to create a query, that will give me all the important information for the invoice. My query looks like this:
SELECT b.OrderID,
b.CustomerID,
c.CompanyName,
c.Address,
c.City,
c.PostalCode,
c.CountryID as CustomersCountryID,
concat(d.FirstName, ' ', d.LastName) as Salesperson,
a.CompanyName as ShippingVia,
e.ProductID,
f.ProductName,
e.Quantity,
e.UnitPrice * e.Quantity * (1 - e.Discount) as ExtendedPrice
from Shippers a
inner join Orders b on a.ShipperID = b.ShipVia
inner join Customers c on c.CustomerID = b.CustomerID
inner join Employees d on d.EmployeeID = b.EmployeeID
inner join [Order Details] e on b.OrderID = e.OrderID
inner join Products f on f.ProductID = e.ProductID
order by b.OrderID
It works, it gives me all the orders made with informations. But now, I need to create a table view for an invoice of particular OrderId. When I write something like this:
CREATE VIEW FAKTURA AS
SELECT b.OrderID,
b.CustomerID,
c.CompanyName,
c.Address,
c.City,
c.PostalCode,
c.CountryID as CustomersCountryID,
concat(d.FirstName, ' ', d.LastName) as Salesperson,
a.CompanyName as ShippingVia,
e.ProductID,
f.ProductName,
e.Quantity,
e.UnitPrice * e.Quantity * (1 - e.Discount) as ExtendedPrice
from Shippers a
inner join Orders b on a.ShipperID = b.ShipVia
inner join Customers c on c.CustomerID = b.CustomerID
inner join Employees d on d.EmployeeID = b.EmployeeID
inner join [Order Details] e on b.OrderID = e.OrderID
inner join Products f on f.ProductID = e.ProductID
WHERE b.OrderID = 10248
I am just creating a separate view file for that particular OrderID. It doesn't look like a real life invoice at all.
It should resemble something like this:
I need to separate general data about invoice and customer from data about order itself, product ID, quantity etc.
Is it possible to create something similar in SQL Server Management Studio? How can I do it?

Your query already provides the header (customer info) and table body parts, so what you could do is (NOTE: this is NOT what I would do but, considering the need to have a very simple solution):
Phrase a query that would perform all the needed calculations for the trailing part based on the INVOICE number (this can be similar to what you already have except that it would SUM the amounts, calculate taxes and shipping cost),
Once you have that query ready, INNER JOIN it to the one you already have (using the invoice ID as a key); Note that you will have to add the additional fields to the top SELECTs list.
The result will be what you already have + the subtotal, tax, shipping and total in each and every record.
Again, this is NOT the most efficient and elegant solution, but matches your needs (simplicity and final result).

Related

How to use select with GROUP BY clause

I have the task.
"For each order, enter the total number of units ordered and the customer's name."
Database: Microsoft SQL Server 12.0.2000.8
I write that code so far:
SELECT a.OrderID, SUM(a.Quantity), c.CompanyName FROM [Order Details] as a
INNER JOIN Orders as b ON b.OrderID = a.OrderID
INNER JOIN Customers as c ON c.CustomerID = b.CustomerID
GROUP BY a.OrderID
But i can not display CompanyName. It should be only one Company Name for each order and we do not need to concat it. How can i do that?
I enclose my database diagram.
The error you're probably getting is that all non-aggregated columns should be present in the GROUP BY clause.
So the mistake is basically in the missing CompanyName column in the GROUP BY.
The query should, thus, look like this:
SELECT
a.OrderID,
SUM(a.Quantity) as TotalQuantity,
c.CompanyName
FROM [Order Details] as a
INNER JOIN Orders as b ON b.OrderID = a.OrderID
INNER JOIN Customers as c ON c.CustomerID = b.CustomerID
GROUP BY a.OrderID, c.CompanyName
Works

SQL-Server, confront Customers with Employees function

I might have a really simple question, but it doesn't seem i can find the solution yet. Basically, i have to write a SQL-Server function, based on Northwind DB. It has to:
Take 2 dates as arguments and display, without repetition these Customer's data ID | Name | City | Address , for those customers where the total purchase he had made from at least one Employee , is greater than the average sale made by this Employee between the two dates.
So the main steps should be:
1. Retrieve the total purchase made from a Customer from each Employee. I know how to get the total purchase from each Company:
SELECT
Customers.CompanyName, SUM(UnitPrice*Quantity)
FROM Orders inner join [Order Details]
ON Orders.OrderID=[Order Details].OrderID INNER JOIN
Customers ON Orders.CustomerID=Customers.CustomerID
GROUP BY Customers.CompanyName
But how can i get those made from each employee?
2.Confront this with the average sales of this Employee between the given dates. I can get the average for each employee:
SELECT FirstName+' '+LastName, AVG(UnitPrice*Quantity)
FROM Orders inner join [Order Details]
ON Orders.OrderID=[Order Details].OrderID
INNER JOIN Employees
ON Orders.EmployeeID=Employees.EmployeeID
WHERE OrderDate BETWEEN #dt1 and #dt2
GROUP BY FirstName+' '+LastName
Note that i'm only pasting the query part, but here, the Employee should depend on the first query (probably this should be put inside a subquery)
Everything should be put inside a single function (it should not be split in two). The Northwind DB diagram is: Northwind Diagram . Please help!
Hope I got the logic right:
create function x (#from datetime, #to datetime)
returns table
as
return (
with cust as (
select o.customerid, o.employeeid, sum(unitprice*quantity) as cust_purchase
from orders o
inner join [order details] d on o.orderid=d.orderid
where o.orderdate between #from and #to
group by o.customerid, o.employeeid
),
emp as (
select o.employeeid, avg(unitprice*quantity) as emp_sale
from orders o
inner join [order details] d on o.orderid=d.orderid
where o.orderdate between #from and #to
group by o.employeeid
)
select c.customerid, c.companyname, c.city, c.address
from cust
inner join emp on cust.employeeid = emp.employeeid
and cust.cust_purchase > emp.emp_sale
inner join customers c on cust.customerid = c.customerid
)
go
select * from x ('19980401', '19980430')

SQL Query on SQL Server 2008

I'm trying to get only customers that ordered both a "Gas Range" and a "Washer". I'm getting Customers who ordered a "Gas Range" and not a "Washer" and customers with both. I need the customer that meets both conditions. I'm close but a little stuck. Below is the query that I have so far. Please let me know if you need more information.
My Tables - CUSTOMER(CUST_NUM, CUST_NAME), ORDER_LINE(ORDER_NUM, PART_NUM), ORDERS(ORDER_NUM, CUST_NUM), PART(PART_NUM, PART_DESCRIPTION)
SELECT C.CUST_NAME AS [Customer(s) that ordered a Gas Range and Washer]
FROM CUSTOMER C
INNER JOIN ORDERS O
ON C.CUST_NUM = O.CUST_NUM
INNER JOIN ORDER_LINE OL
ON O.ORDER_NUM = OL.ORDER_NUM
INNER JOIN PART P
ON OL.PART_NUM = P.PART_NUM
WHERE P.PART_DESCRIPTION IN ('GasRange','Washer')
GROUP BY C.CUST_NAME
try the following
SELECT C.CUST_NAME AS [Customer(s) that ordered a Gas Range and Washer]
FROM CUSTOMER C
INNER JOIN ORDERS O
ON C.CUST_NUM = O.CUST_NUM
INNER JOIN ORDER_LINE OL
ON O.ORDER_NUM = OL.ORDER_NUM
INNER JOIN PART P
ON OL.PART_NUM = P.PART_NUM
INNER JOIN ORDERS O2
ON C.CUST_NUM = O2.CUST_NUM
INNER JOIN ORDER_LINE OL2
ON O2.ORDER_NUM = OL2.ORDER_NUM
INNER JOIN PART P2
ON OL2.PART_NUM = P2.PART_NUM
WHERE P.PART_DESCRIPTION IN ('GasRange') and P2.PART_DESCRIPTION IN ('Washer')
GROUP BY C.CUST_NAME
EDIT: Had a further look and I'm afraid that this can't be simplified in any other way than using WITH and complicated aggregate functions, which I would say would be more complicated than this - I think the other solution suggested using WITH won't work - it joins incorrectly. You definitely can't remove order line, and you have to use the order twice as well - if it was used once, it will cover only when the customer ordered it within one order, which is not what you wanted ;)
Try this...
So basically you need to join your Parts table again to ensure the same customer ordered a "Gas Range" and a "Washer". An IN, like in your current query functions as an OR therefore you are not getting the expected result.
WITH CTE AS (
SELECT DISTINCT O.CUST_NUM FROM ORDERS O
INNER JOIN ORDER_LINE OL
ON O.ORDER_NUM = OL.ORDER_NUM
INNER JOIN PART P
ON OL.PART_NUM = P.PART_NUM
INNER JOIN PART P2
ON OL.PART_NUM = P2.PART_NUM
WHERE P.PART_DESCRIPTION IN ('GasRange')
AND P2.PART_DESCRIPTION IN ('Washer')
)
SELECT C.CUST_NAME AS [Customer(s) that ordered a Gas Range and Washer]
FROM CUSTOMER C
INNER JOIN CTE O
ON C.CUST_NUM = O.CUST_NUM

Oracle: Using Sub-Queries, JOIN and distinct function together

Here is how I contructed the step-by-step:
M1. create a sub-query that will return CustomerId and total invoiced for that customer
M2. A second subquery that will give a list of distinct ProductIDs (along with product SKUs) and CustomerIDs.
M3. The M1 and M2 subqueries will be joined to make association between customer totals and products (for the same CustomerId).
M4. The query M3 will be fed to the final query that will just find the top 5 products.
I'm stuck on creating the distinct ProductID and customerID because they would have to be in aggregate functions in order to make them distinct.
Attached is an image that is the erwin diagram which helps understand the system.
If you can help me with M1-M4, I will greatly appreciate it. I'm not a programmer by trade but a business analyst.
--M1--
select C.CustomerId, COUNT(I.InvoiceId) TotalNumInvoices
from Customer C
JOIN Invoice I ON (I.CustomerId = C.CustomerId)
group by C.CustomerId
--M2: Incomplete--
select P.ProductID, P.SKU, C.CustomerID
from Product P
JOIN InvoiceLine IL ON (IL.ProductId = P.ProductId)
JOIN Invoice I ON (IL.InvoiceId = I.InvoiceId)
JOIN Customer C ON (C.CustomerId = I.CustomerId)
you can also use the DISTINCT keyword your select clause in order to get unique values. Try this for m2:
select DISTINCT p.productID, p.sku, i.customerID
from invoice i INNER JOIN invoiceLine il
ON i.invoiceID = il.invoiceID
JOIN product p
ON il.productID = p.productID;

TSQL basic join on Northwind database

I am learning TSQL (well, just SQL to tell the truth) and I want to make Employee - Product statistic on Northwind database.
Expected results should be something like:
EmployeeID | ProductID | income
1 | 1 | 990
1 | 2 | 190
1 | 3 | 0
...
For all Employy-Product pairs
My first try is this query:
SELECT E.EmployeeID, OE.ProductID, SUM(OE.ExtendedPrice) as income
FROM [Order Details Extended] OE
JOIN [Orders] O
ON OE.OrderID = O.OrderID
RIGHT OUTER JOIN Employees E
ON E.EmployeeID = O.EmployeeID
GROUP BY E.EmployeeID, OE.ProductID
ORDER BY E.EmployeeID
But I don't get results for all pairs.
What am I doing wrong?
HLGEM missed few columns but I understood what he tried to do.
I came up with this:
SELECT A.employeeid, A.productid, SUM(Oe.ExtendedPrice) AS income
FROM
(SELECT E.Employeeid, P.productid
FROM employees E
CROSS JOIN products P) A
LEFT JOIN [Order Details Extended] OE
ON A.productid = OE.productid
LEFT JOIN [Orders] O
ON OE.OrderID = O.OrderID
GROUP BY A.EmployeeID, A.ProductID
ORDER BY A.EmployeeID, A.ProductID
This returns results for all pairs, but those don't seem right.
For example above query returns as first row:
1, 1, 12788.10
But this query:
SELECT SUM(ODE.ExtendedPrice) FROM [Order Details Extended] ODE
LEFT JOIN [Orders] OD
ON ODE.OrderID = OD.OrderID
WHERE OD.EmployeeID = 1 AND ODE.ProductID = 1
Returns 990.90.
Why?
edit
I got it finally:
SELECT A.EmployeeId, A.ProductId, ISNULL(SUM(Oe.ExtendedPrice), 0) AS income
FROM
(SELECT E.Employeeid, P.productid
FROM [Employees] E
CROSS JOIN [Products] P) A
LEFT JOIN [Orders] O
ON O.EmployeeID = A.EmployeeID
LEFT JOIN [Order Details Extended] OE
ON A.productid = OE.productid AND OE.OrderID = O.OrderID
GROUP BY A.EmployeeID, A.ProductID
ORDER BY A.EmployeeID, A.ProductID
#HLGEM you can copy/paste this solution to your answer so I can accept it.
You could try:
SELECT A.employeeid,A.product_id, SUM(Oe.ExtendedPrice) AS income
FROM
(SELECT E.Employeeid, P.product id
FROM employee E
CROSS JOIN product p) A
LEFT JOIN [Order Details Extended] OE
ON A.EmployeeID = O.EmployeeID
LEFT JOIN [Orders] O
ON OE.OrderID = O.OrderID
GROUP BY A.EmployeeID, OE.ProductID
ORDER BY A.EmployeeID
I switched it to a LEFT JOIN as most people use them instead of right joins and thus they are easier for maintenance.
What results are you missing? It looks like you have used an inner join between Order Details Extended and Orders, so any orders that don't have details will be excluded. It seems logical that you would want this, since you are summing a value in the details table.
Then you do a right outer join with Employees, so you are including all employees, regardless of whether they have any orders. This also makes sense, since it looks as though you are seeing which employees sold which products.
Your query will only give you the data for products that the employees have actually sold. If you are looking for all employee-product combinations, regardless of whether the employee had ever sold that product, you will want to join the Product table as well, although in my muddled morning, I can't think if you would want an outer join or a cross join.
In all, I think your first try is a good one. Pretty complex for a beginner. Nice effort!