TSQL Query Help Pt. III (Last) - sql-server

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

Related

sql server - How to Get all distinct value in group by column from two table and count from another table for each value

I have 3 tables in that 2 tables are master table and 3rd is transaction table. i need to get count from transaction table for each value in other two table without loosing rows in mater table
i need result like below
Table layout for understanding
This is the code i have tried,
select s.status_name, e.machine_group_name, qty = COALESCE(COUNT(e.id),0)
from tbl_status s
left outer JOIN tbl_transaction as e ON e.status_name = s.status_name
group by e.machine_group_name, s.status_name
This is solution i have figured:
select m.machine_group_name, s.status_name, qty = COUNT(e.id) from
tbl_machine_group as m
cross join tbl_status as s
left outer join tbl_transaction as e on e.status_name = s.status_name
and e.machine_group_name = m.machine_group_name
group by m.machine_group_name, s.status_name
order by machine_group_name
select
MC_Group_Name
,Status_Name
,count(1) as [Count of Transaction]
from
tbl_Transaction tbl_3
left join tbl_Machine_Group tbl_1
on tbl_3.MC_Group_Name = tbl_1.MC_Group_Name
left join tbl_Status tbl_2
on tbl_3.Status_Name = tbl_2.Status_Name
group by
MC_Group_Name
,Status_Name

SQL Server - Combining rows in View

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.

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.

How to join additional table when left outer not working

I have an existing proc which I have chopped up for brevity's sake
SELECT col1, col2
FROM (
col1, col2
SELECT col3--aggregate columns
FROM iep i
INNER JOIN student s ON s.studentID = i.studentID
INNER JOIN dbo.IDuration id ON i.IepID = id.iepID
INNER JOIN AppointmentStudent as ON s.studentID = as.studentID
INNER JOIN Appointment a ON as.appointmentID = a.appointmentID
INNER JOIN AppointmentTherapist at ON a.appointmentID = at.appointmentID
WHERE s.studentID = #studentID
GROUP BY col1, col2
) t
The aggregate columns summarizes appointments into the weeks of the year, but it only does sos for the weeks the student had appointments. I have an additional table called SchoolWeekYear that is populated with all of the weeks of the year that I am trying to integrate to this proc so I get 52 records back and not just the handful I am currently getting.
SELECT col1, col2
FROM (
col1, col2
SELECT col3--aggregate columns
FROM iep i
INNER JOIN student s ON s.studentID = i.studentID
INNER JOIN dbo.IDuration id ON i.IepID = id.iepID
INNER JOIN AppointmentStudent as ON s.studentID = as.studentID
INNER JOIN Appointment a ON as.appointmentID = a.appointmentID
LEFT OUTER JOIN SchoolWeekYear swy on a.calWeekNumber = swy.calWeekNumber
INNER JOIN AppointmentTherapist at ON a.appointmentID = at.appointmentID
WHERE s.studentID = #studentID
GROUP BY col1, col2
) t
Is this possible?
You need to integrate SchoolWeekYear into the existing table set at an earlier stage.
To show you the principle, let us simplify the problem even further. Let there be a table called WeeklyData with columns WeekNumber and SomeData. Some weeks might have multiple entries, some others none. So this query
SELECT
WeekNumber,
AGG(SomeData)
FROM
WeeklyData
GROUP BY
WeekNumber
;
would return only weeks present in WeeklyData. If you want to return data for all weeks, use a corresponding reference table (let it be called AllWeeks) like this:
SELECT
aw.WeekNumber,
AGG(wd.SomeData)
FROM
AllWeeks AS aw
LEFT JOIN
WeeklyData AS wd ON aw.WeekNumber = wd.WeekNumber
GROUP BY
aw.WeekNumber
;
So, you take the reference table (AllWeeks) and join the data table (WeeklyData) to it, not the other round.
Now, what if the original query was slightly more complex? Let us now suppose the data table is called StudentWeeklyData and has a column called StudentID which is a reference to a Students table. Let us also imagine the query is similar to yours in that it logically includes the Students table before the data table is joined and filters the results on the primary key of Students:
SELECT
s.StudentID,
s.StudentName,
swd.WeekNumber,
AGG(swd.SomeData)
FROM
Students AS s
INNER JOIN
StudentWeeklyData AS swd ON s.StudentID = swd.StudentID
WHERE
s.StudentID = #StudentID
GROUP BY
s.StudentID,
s.StudentName,
swd.WeekNumber
;
(Not every detail matters here, I just wanted to use a more similar example for you that would still be simple enough to understand.) Again, this would return only weeks where the specified student has data in StudentWeeklyTable. If you wanted to return all weeks for the student (some of them potentially empty, of course), this is how you could go about it:
SELECT
s.StudentID,
s.StudentName,
aw.WeekNumber,
AGG(swd.SomeData)
FROM
Students AS s
CROSS JOIN
AllWeeks AS aw
LEFT JOIN
StudentWeeklyData AS swd ON s.StudentID = swd.StudentID
AND aw.WeekNumber = swd.WeekNumber
WHERE
s.StudentID = #StudentID
GROUP BY
s.StudentID,
s.StudentName,
aw.WeekNumber
;
Here you can see again that the AllWeeks table is included before the data table. The difference to the previous case is we are not left-joining the result of the join between Students and StudentWeekly to AllWeeks, nor are we left-joining the data table itself specifically to AllWeeks. Instead, the data table is joined to the result of a cross join, Students × AllWeeks.
Returning to your specific situation, I realise that in your case even more tables are involved. Since you are not specifying how all those tables are related to one another, I can only guess that SchoolWeekYear should be cross-joined somewhere after FROM and before this line:
INNER JOIN Appointment a ON as.appointmentID = a.appointmentID
and that the said line should be modified like this:
LEFT JOIN Appointment a ON as.appointmentID = a.appointmentID
AND swy.calWeekNumber = a.calWeekNumber
the swy being an alias assigned to SchoolWeekYear.
It is also worth noting that there is a subsequent inner join with AppointmentTherapist. That join would eliminate the effect of the above left join if it remained unchanged, because its condition references the Appointment table. Perhaps, the syntactically easiest way to fix the issue would be to change that inner join to a left one too, although there is another way: instead of
LEFT JOIN Appointment a ON as.appointmentID = a.appointmentID
AND swy.calWeekNumber = a.calWeekNumber
LEFT JOIN AppointmentTherapist at ON a.appointmentID = at.appointmentID
you could use this syntax:
LEFT JOIN
Appointment a
INNER JOIN AppointmentTherapist at ON a.appointmentID = at.appointmentID
ON as.appointmentID = a.appointmentID
AND swy.calWeekNumber = a.calWeekNumber
That way the logical order of joining would be changed: Appointment and AppointmentTherapist would be first inner-joined with each other, then the result set would be outer-joined to the result of the previously specified joins.
It is possible. But if you have multiple row with some calWeekNumber on the SchoolWeekYear table, your aggregate function return wrong result.
If you want all lines in SchoolWeekYear shown, regardless of a match, you should use RIGHT OUTER JOIN instead of LEFT.

Counting grouped records from multiple tables

there is a column comment_id of a table called pic_alb_love which i'd like to add to the query below but i don't know how. Actually what i want to do is to count the total comment_id of the table pic_alb_love.
SELECT users_pics.wardrobe,
profile.fname,
users_pics.pic,
users_pics.u_pic_id,
users_pics.email,
users_pics.make,
users_pics.designer,
photo_comment.comment,
max_photo_comment.count_pic_id
FROM dbo.users_pics
INNER JOIN profile
ON users_pics.email = profile.email
LEFT Join (SELECT pic_id
,MAX(comment_id) max_comment_id
,COUNT(pic_id) count_pic_id
FROM photo_comment
GROUP BY pic_id
) max_photo_comment
On users_pics.u_pic_id = max_photo_comment.pic_id
LEFT Join photo_comment
On max_photo_comment.pic_id = photo_comment.pic_id
AND max_photo_comment.max_comment_id = photo_comment.comment_id
WHERE users_pics.wardrobe = MMColParam
AND users_pics.email = MMColParam2
ORDER BY u_pic_id asc
these are the various fields of the table pic_alb_love:
(comment_id,pic,love_com, wardrobe, email
,com_name,resp_email, play_count, com_stat)
LEFT JOIN (SELECT Pic
,Count(*) [CommentCount]
FROM pic_alb_love
GROUP BY Pic) c
ON c.Pic=u_pic_id
Assuming that pic_alb_love.pic is the FK on the table...
Use [CommentCount] in the select list.

Resources