SQL Server - Combining rows in View - sql-server

I am creating a view that is supposed to show the full details for a pizza per OrderID. Although when I run my view its printing out two rows for OrderID because it has more than one topping. How can I combine those rows in my view so both toppings will show under the "ToppingsDescription" column and the "Total Price" column will be updated (Large pizza = $15 and $0.30 per topping so the updated price should be 15.60 for the large and two toppings). Any suggestions on what to do?
CREATE VIEW PizzaPerOrder_vw
AS
SELECT PO.PizzaOrderID, PizzaSizeDesc, PizzaSpecialInstructions, ToppingsDescription, SUM(T.ToppingsPrice + PizzaSizePrice) AS 'Total Price'
FROM dbo.PizzaOrder AS PO
INNER JOIN dbo.Pizza AS P ON PO.PizzaOrderID = P.PizzaOrderID
INNER JOIN dbo.PizzaSpecialInstructions AS PI ON P.PizzaID = PI.PizzaID
INNER JOIN dbo.PizzaToppings AS PT ON P.PizzaID = PT.PizzaID
INNER JOIN dbo.Toppings AS T ON PT.ToppingsID = T.ToppingsID
INNER JOIN dbo.PizzaSize AS PS ON P.PizzaSizeID = PS.PizzaSizeID
GROUP BY PO.PizzaOrderID, PS.PizzaSizeDesc, PI.PizzaSpecialInstructions, T.ToppingsDescription;

In SQL Server 2017 there's a new aggregate function named STRING_AGG:
CREATE VIEW PizzaPerOrder_vw
AS
SELECT PO.PizzaOrderID, PizzaSizeDesc, PizzaSpecialInstructions,
STRING_AGG(ToppingsDescription, ',') AS Toppings,
SUM(T.ToppingsPrice) + MAX(PizzaSizePrice) AS 'Total Price'
FROM dbo.PizzaOrder AS PO
INNER JOIN dbo.Pizza AS P ON PO.PizzaOrderID = P.PizzaOrderID
INNER JOIN dbo.PizzaSpecialInstructions AS PI ON P.PizzaID = PI.PizzaID
INNER JOIN dbo.PizzaToppings AS PT ON P.PizzaID = PT.PizzaID
INNER JOIN dbo.Toppings AS T ON PT.ToppingsID = T.ToppingsID
INNER JOIN dbo.PizzaSize AS PS ON P.PizzaSizeID = PS.PizzaSizeID
GROUP BY PO.PizzaOrderID, PS.PizzaSizeDesc, PI.PizzaSpecialInstructions;
This returns the toppings in random order, if you want a specific order:
STRING_AGG(ToppingsDescription, ',') WITHIN GROUP (ORDER BY ToppingsDescription) AS Toppings
It might be more efficient to aggregate the PizzaToppings before the join using a CTE.

Related

Extract Specific Data After a aggregation (Or any other solution for the desired result)

I want to select the Total "sales" of a specific "main_category" for the year 2016
(main categories that don't have sales in that year should appear as zero)
I have managed to select the "sales" of a specific "main category" with all the other "main_categories" (that doesn't have any sales) appearing as zero using below query:
SELECT
mc.name,
ISNULL(SUM(s.no_of_units * b.unit_price),0) AS tCatSales
FROM Sales s
INNER JOIN Invoice i ON i.invoice_ID = s.invoice_id
INNER JOIN Inventory inv ON inv.inventory_ID = s.inventory_ID
INNER JOIN Batch b ON b.batch_ID = inv.batch_ID
INNER JOIN Products p ON p.product_id = b.product_ID
INNER JOIN Category c ON c.category_ID = p.category_id
RIGHT JOIN Main_Category mc ON mc.cat_id = c.main_category
--WHERE YEAR(i.trans_date) = 2016
GROUP BY mc.name
--HAVING YEAR(i.trans_date)=2016
but when I try to further segregate it for year 2016 ONLY either by WHERE clause or HAVING clause, it stops showing "main_category" names that have zero sales in the year.
One thing that I can think of is to give the query invoices only from 2016
which I tried to did by doing something like,
Replacing the line:
INNER JOIN Invoice i ON i.invoice_ID = s.invoice_id
with:
INNER JOIN Invoice i ON i.invoice_ID IN (SELECT invoice_id FROM Invoice in2 WHERE Year(in2.trans_date)=2016)
which did display the categories with zero values but with increased the calculated Sales Amount (from 2069 to something 203151022.75).
I understand this addition is somewhat illogical and disrupts the whole Inner Joins but so far these are the closest thing I can think of or find on the web.
I REPEAT the desired result is: main categories that don't have sales in that year should appear as zero with the year given year/month/date
As Sean and Eli mentioned, RIGHT JOIN is not recommended, you may change it to LEFT JOIN, OR use subquery like this:
SELECT
mc.name,
tCatSales = ISNULL(
(
SELECT
SUM(s.no_of_units * b.unit_price) AS tCatSales
FROM Sales s
INNER JOIN Invoice i ON i.invoice_ID = s.invoice_id
INNER JOIN Inventory inv ON inv.inventory_ID = s.inventory_ID
INNER JOIN Batch b ON b.batch_ID = inv.batch_ID
INNER JOIN Products p ON p.product_id = b.product_ID
INNER JOIN Category c ON c.category_ID = p.category_id
WHERE mc.cat_id = c.main_category
AND YEAR(i.trans_date) = 2016
) , 0)
FROM Main_Category mc
try this:
WHERE ISNULL(YEAR(i.trans_date), 1) = 2016
if you put simple equals conditions on outer join it will eliminate nulls, which give zero-valued rows you desire.
Also note that something like:
WHERE YEAR(i.trans_date) = 2016
is not sargable, see here

GROUP BY clause on multiple joins

I need to show Class Wise attendance like this
IN DB i am have separate table (studentattendance) ,which store attendance like this
I Just Need to Show Total students Present Per Class
I try to do Query which give output like this
this is my query
SELECT distinct CM.ClassName ,SB.SubjectName ,(select count(studentattendance.Day1) from studentattendance where day1 = 'P') as Present, convert(varchar(10),AttendanceDate ,126) as AttendancetimeTaken
from studentattendance SA inner join studentmaster SM on SA.StudentID=SM.ID join ProfessorMaster p on SA.ProfessorID =p.Id
join Classmaster CM on SA.ClassID = CM.ID inner join SubjectMaster SB on SA.SubjectID =SB.ID
I need to Group Class Wise . how can I do it
By not having the actual tables, I tried the following modifications, please try it and reply me
SELECT CM.ClassName ,
SB.SubjectName , count(SA.Day1) as Present,
convert(varchar(10),AttendanceDate , 126) as AttendancetimeTaken
from studentattendance SA
inner join studentmaster SM on SA.StudentID=SM.ID
join ProfessorMaster p on SA.ProfessorID =p.Id
join Classmaster CM on SA.ClassID = CM.ID
inner join SubjectMaster SB on SA.SubjectID =SB.ID
where SA.day1 = 'P'
group by CM.ClassName, SB.SubjectName, AttendanceDate

MS SQL Table Joins - Multiple Tables

I am new to MS SQL and am having trouble joining 4 tables within a query.
I am trying to join Orders, Order Lines, Client, and Picked tables to create a query to show quantity ordered and picked for a client. If I comment out the last inner join for Picked, I get the correct results. When I include the inner join for Picked the query returns results but data that should be in the Picked fields is NULL. One order line can have 1 or more Picked lines.
SELECT W_Warehouse, OH.OrderID, OH.RequiredDate, C.Client, OL.LineNbr, OL.QtyOrd, P.QtyPick
FROM Order
INNER JOIN Warehouse on Order.OH_WHS = Warehouse.W_PK
INNER JOIN Client on Order.O_Client = Client.C_PK
INNER JOIN OrderLine on Order.O_PK = OrderLine.OL_PK
INNER JOIN Picked on OrderLine.O_PK = Picked.P_PK
WHERE C.CLIENT = 'WENDYS'
Without knowing the data in the tables it is difficult to answer precisely.
But as you say you have 1+ rows in the Picked table, you probably want to do aggregation with GROUP BY and SUM()
Maybe this is what you're looking for:
SELECT
W.W_Warehouse,
OH.OrderID,
OH.RequiredDate,
C.Client,
OL.LineNbr,
OL.QtyOrd,
P.QtyPick
FROM
Order OH
INNER JOIN Warehouse W on OH.OH_WHS = W.W_PK
INNER JOIN Client C on OH.O_Client = C.C_PK
INNER JOIN OrderLine OL on OH.O_PK = OL.OL_PK
CROSS APPLY (
select sum(QtyPick) as QtyPick
from Picked P
where OL.O_PK = P.P_PK
) P
WHERE
C.CLIENT = 'WENDYS'
It calculates the sum of QtyPick separately so it doesn't increase the number of lines in the result.

Group By not working in SQL Server

CREATE VIEW [dbo].[Payment_Transaction_vw]
AS
SELECT payment_trans_id,
Student_Info.student_fname,
Student_Info.student_lname,
Student_Info.ID_Number,
Trimester_Payment.deadline,
Transaction_Info.trans_name,
Payment_Transaction.amount,
Payment_Transaction.date_paid
FROM [Payment_Transaction]
INNER JOIN Student_Info
ON Payment_Transaction.student_info_id = Student_Info.student_info_id
INNER JOIN Trimester_Payment
ON Payment_Transaction.trimester_id = Trimester_Payment.trimester_id
INNER JOIN Transaction_Info
ON Payment_Transaction.trans_info_id = Transaction_Info.trans_info_id
GROUP BY ID_Number,trans_name;
That is my script to make a view in sql server in visual studio, I wanted to group the ID_Number & trans_name which have a repeating values in the table Payment_Transactions. I wanted that this ID_Number with the trans_name will only displayed once. I also want to sum up the amount paid for every ID_number with the same trans_name.
When using group by you want to make sure that any unique value will be aggregated or consolidated so that it can be displayed in one row. As it is right now, payment_trans_id (and others) are still unique and since you chose to display these the group by cannot be done.
What do you want to do with payment_trans_id, date_paid, amount ... all other columns really?
Example using MAX(), MIN() and AVG():
SELECT
MAX(payment_trans_id) AS payment_trans_id,
Transaction_Info.trans_name,
Student_Info.ID_Number,
AVG(Payment_Transaction.amount) AS amount,
MIN(Payment_Transaction.date_paid) AS date_paid
FROM [Payment_Transaction]
INNER JOIN Student_Info ON Payment_Transaction.student_info_id = Student_Info.student_info_id
INNER JOIN Trimester_Payment ON Payment_Transaction.trimester_id = Trimester_Payment.trimester_id
INNER JOIN Transaction_Info ON Payment_Transaction.trans_info_id = Transaction_Info.trans_info_id
GROUP BY ID_Number, trans_name;
For support in EF, perhaps this will be sufficient (perhaps not):
SELECT
ISNULL(MAX(payment_trans_id),0) AS Id,
Transaction_Info.trans_name,
Student_Info.ID_Number,
AVG(Payment_Transaction.amount) AS amount,
MIN(Payment_Transaction.date_paid) AS date_paid
FROM [Payment_Transaction]
INNER JOIN Student_Info ON Payment_Transaction.student_info_id = Student_Info.student_info_id
INNER JOIN Trimester_Payment ON Payment_Transaction.trimester_id = Trimester_Payment.trimester_id
INNER JOIN Transaction_Info ON Payment_Transaction.trans_info_id = Transaction_Info.trans_info_id
GROUP BY ID_Number, trans_name;
You have to aggregate columns that are not in group by clause.
As example, which one of date_paid (for payment_trans_id = 1 and 2) you want to return? 6/25/2015 or 5/6/2015? SQL server cant know, so you get multiple rows.

TSQL Query Help Pt. III (Last)

I have 2 queries I got from the help from this site and they are:
SELECT gr.g_name, (DATEDIFF(d, r.res_checkout_date, r.res_checkin_date) * pp.rate ) + ISNULL(i.inv_amount, 0)
FROM guest_reservation gr LEFT OUTER JOIN invoice i ON gr.confirm_no = i.confirm_no
JOIN reservation r ON gr.confirm_no = r.confirm_no
JOIN price_plan pp ON r.price_plan = pp.price_plan;
SELECT g.g_name, DATEDIFF(d, r.res_checkin_date, r.res_checkout_date)*p.rate+coalesce(i.inv_amount, 0) as Amount
FROM reservation as r INNER JOIN priceplan as p
ON r.price_plan = p.price_plan
INNER JOIN guest_reservation as g
ON r.confirm_no = g.confirm_no
LEFT OUTER JOIN invoice as i
ON r.confirm_no = i.confirm_no;
All the tables have the following data associated with them:
The guest reservation table has the following columns with data:
(confirm_no, agent_id, g_name, g_phone)
The reservation table has the following columns with data:
(confirm_no, credit_card_no, res_checkin_date, res_checkout_date,
default_villa_type, price_plan)
I need to somehow add items that a guest has ordered from the dining_order table (which is linked with the r_confirm_no from the dining_order table equaling the confirm_no from the reservation table), the items price must be taken from the dining_menu table (where dining_order.item equals dining_menu.item) and added into the above query.
The associated tables with the new information I need to add is:
The invoice table has the following columns with data:
(inv_no, inv_date, inv_amount, confirm_no).
The price plan table has the following columns with data:
(price_plan, rate, default_villa_type, bed_type)
This is untested but you could use a subquery to sum the dining items for each guest and add that to the total. This is also an outer join as the guest might not have made use of the dining facilities.
SELECT gr.g_name, (DATEDIFF(d, r.res_checkout_date, r.res_checkin_date) * pp.rate ) + ISNULL(i.inv_amount, 0) + ISNULL(d.total_dining, 0)
FROM guest_reservation gr
LEFT OUTER JOIN invoice i ON gr.confirm_no = i.confirm_no
JOIN reservation r ON gr.confirm_no = r.confirm_no
JOIN price_plan pp ON r.price_plan = pp.price_plan
LEFT OUTER JOIN (SELECT r_confirmation_no, SUM(price) AS total_dining
FROM dining_order do JOIN dining_menu dm ON do.item = dm.item
GROUP BY r_confirmation_no) AS d ON d.r_confirmation_no = r.confirm_no

Resources