How to build the SQL query for given question? - sql

I have 2 SQL problems for which I need SQL query.
Table - Booking
Table - Adventure
Table - Tourist
Table - Location
Query1: Display TourId, TourName and Email of those tourist(s) who have booked all types of adventures. (Hint: Use the concept of Joins).
My Try:
Select DISTINCT T.TourId, T.TourName, T.Email
From Tourist T
INNER JOIN Booking B ON B.TourId = T.TourId
INNER JOIN Location L ON L.LocId = B.Loc
INNER JOIN Adventure A ON A.AdvId = L.AdvId
AND A.AdvType in (Select DISTINCT AdvType From Adventure)
Query2: For each booking, Identify the location whose bookingamount is greater than the average bookingamount of all the bookings done for that location. Display LocId, LocName and Rating for the identified location(s). (Hint: Use the concept of subqueries)
My Try:
Select B.Loc, L.LocName, L.Rating
From Booking B
INNER JOIN Location L ON B.Loc = L.LocId
AND BookingAmount > (Select AVG(B.BookingAmount) from Booking B Group By B.Loc)

Query 1:
select distinct tourid,tourname,email from tourist, booking, location
where 1=1
and tourist.tourid = booking.tourid
and booking.locid = location.locid
and location.advid = adventure.advid
and adventure.advtype = 'A'
Query 2:
select locid,locname,rating
from location
where locid in (select booking.locid from booking, (select
b.bookid,b.loc,avg(b.bookingamount) as avg_ba from booking b group by
b.bookid,b.loc) aa
where booking.bookid = aa.bookid and booking.loc = aa.loc and
booking.bookingamount > aa.avg_ba)
Note: if it is a database design for any production server, I must say it needs to be changed ASAP.
Another Note: Please do not ever use pictures as references. It is very difficult to get information from pictures

Query 1:-
Select DISTINCT T.TourId, T.TourName, T.Email
From Tourist T
INNER JOIN Booking B ON B.TourId = T.TourId
INNER JOIN Location L ON L.LocId = B.Loc
INNER JOIN Adventure A ON A.AdvId = L.AdvId
WHERE A.AdvType='A' AND A.AdvType='G' AND A.AdvType='W';
Query 2:-
Select B.Loc, L.LocName, L.Rating
From Booking B
INNER JOIN Location L ON B.Loc = L.LocId
WHERE B.BookingAmount > (Select AVG(B.BookingAmount) from Booking B Group By B.Loc);

Related

Access Subquery On mulitple conditions

This SQL query needs to be done in ACCESS.
I am trying to do a subquery on the total sales, but I want to link the sale to the province AND to product. The below query will work with one or the other: (po.product_name = allp.all_products) AND (p.province = allp.all_province); -- but it will no take both.
I will be including every month into this query, once I can figure out the subquery on with two criteria.
Select
p.province as [Province],
po.product_name as [Product],
all_price
FROM
(purchase_order po
INNER JOIN person p
on p.person_id = po.person_id)
left join
(
select
po1.product_name AS [all_products],
sum(pp1.price) AS [all_price],
p1.province AS [all_province]
from (purchase_order po1
INNER JOIN product pp1
on po1.product_name = pp1.product_name)
INNER JOIN person p1
on po1.person_id = p1.person_id
group by po1.product_name, pp1.price, p1.province
)
as allp
on (po.product_name = allp.all_products) AND (p.province = allp.all_province);
Make the first select sql into a table by giving it an alias and join table 1 to table 2. I don't have your table structure or data to test it but I think this will lead you down the right path:
select table1.*, table2.*
from
(Select
p.province as [Province],
po.product_name as [Product]
--removed this ,all_price
FROM
(purchase_order po
INNER JOIN person p
on p.person_id = po.person_id) table1
left join
(
select
po1.product_name AS [all_products],
sum(pp1.price) AS [all_price],
p1.province AS [all_province]
from (purchase_order po1
INNER JOIN product pp1
on po1.product_name = pp1.product_name)
INNER JOIN person p1
on po1.person_id = p1.person_id
group by po1.product_name, pp1.price, p1.province --check your group by, I dont think you want pp1.price here if you want to aggregate
) as table2 --changed from allp
on (table1.product = table2.all_products) AND (table1.province = table2.all_province);

sql subquery join group by

I am trying to get a list of our users from our database along with the number of people from the same cohort as them - which in this case is defined as being from the same medical school at the same time.
medical_school_id is stored in the doctor_record table
graduation_dt is stored in the doctor_record table as well.
I have managed to write this query out using a subquery which does a select statement counting the number of others for each row but this takes forever. My logic is telling me that I ought to run a simple GROUP BY query once first and then somehow JOIN the medical_school_id on to that.
The group by query is as follows
select count(ca.id) , cdr.medical_school_id, cdr.graduation_dt
from account ca
LEFT JOIN doctor cd on ca.id = cd.account_id
LEFT JOIN doctor_record cdr on cd.gmc_number = cdr.gmc_number
GROUP BY cdr.medical_school_id, cdr.graduation_dt
The long select query is
select a.id, a.email , dr.medical_school_id,
(select count(ba.id) from account ba
LEFT JOIN doctor bd on ba.id = bd.account_id
LEFT JOIN doctor_record bdr on bd.gmc_number = bdr.gmc_number
WHERE bdr.medical_school_id = dr.medical_school_id AND bdr.graduation_dt = dr.graduation_dt) AS med_count,
from account a
LEFT JOIN doctor d on a.id = d.account_id
LEFT JOIN doctor_record dr on d.gmc_number = dr.gmc_number
If you could push me in the right direction that would be amazing
I think you just want window functions:
select a.id, a.email, dr.medical_school_id, dr.graduation_dt,
count(*) over (partition by dr.medical_school_id, dr.graduation_dt) as cohort_size
from account a left join
doctor d
on a.id = d.account_id left join
doctor_record dr
on d.gmc_number = dr.gmc_number;
Using your same code for group by:
SELECT * FROM (
(
SELECT acc.[id]
, acc.[email]
FROM
account acc
LEFT JOIN
doctor doc
ON
acc.id = doc.account_id
LEFT JOIN
doctor_record doc_rec
ON
doc.gmc_number = doc_rec.gmc_number
) label
LEFT JOIN
(
SELECT count(acco.id)
, doc_reco.medical_school_id
, doc_reco.graduation_dt
FROM
account acco
LEFT JOIN
doctor doct
ON
acco.id = doct.account_id
LEFT JOIN
doctor_record doc_reco
ON
doct.gmc_number = doc_reco.gmc_number
GROUP BY
doc_reco.medical_school_id,
doc_reco.graduation_dt
) count
ON
count.[medical_school_id]=label.[medical_school_id]
AND
count.[graduation_dt]=label.[graduation_date]
)
how about something like this?
select a.doctor_id
, count(*) - 1
from doctor_record a
left join doctor_record b on a.medical_school_id = b.medical_school_id
and a.graduation_dt = b.graduation_dt
group by a.doctor_id
Subtract 1 from the count so that you're not counting the doctor in the "other folks in same cohort" number
I'm defining "same cohort" as "same medical school & graduation date".
I'm unclear on what GMC number is and how it is related. Is it something to do with cohort?

Return rows where a customer bought things on same day

Can someone help me with the rest of my Query.
This query gives me Customer, AdressNr, Date, Employee, Article, ActivityNr
from all the sales in my Company.
SELECT ad.Name + ' ' + ad.Vorname AS Customer,
pa.Kunde AS CustomerNr,
CONVERT(VARCHAR(10),p.datum,126) AS Date,
(SELECT a.name + ' ' + a.Vorname AS Name FROM PRO_Mitarbeiter m LEFT JOIN ADR_Adressen a ON a.AdressNrADR=m.AdressNrADR WHERE m.MitNrPRO = l.MitNrPRO) as Employee,
p.Artikel_1 AS Article,
l.AufgabenNrCRM AS OrderNr
FROM ZUS_Therapie_Positionen p
INNER JOIN CRM_AufgabenLink l ON l.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN CRM_Aufgaben ab ON ab.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN PRO_Auftraege pa ON pa.AuftragNrPRO = ab.AuftragNrPRO
INNER JOIN ADR_Adressen ad ON ad.AdressNrADR = pa.Kunde
INNER JOIN ADR_GruppenLink gl ON gl.AdressNrADR = ad.AdressNrADR
INNER JOIN ADR_Gruppen g ON g.GruppeADR = gl.GruppeADR
WHERE l.MitNrPRO != 0
GROUP BY l.AufgabenNrCRM,ad.Name,ad.Vorname,pa.Kunde,p.datum,p.Artikel_1,l.MitNrPRO
ORDER BY pa.Kunde,p.datum,l.AufgabenNrCRM
My goal is to filter this so i get only rows back where the customer has bought more then 1 Thing on the same day. It doesn't matter if a customer bought the same Article twice on the same day. I want too see this also.
It's to complicated to write some SQL Fiddle for you but in this Picture you can see what my goal is. I want to take away all rows with an X on the left side and thoose with a Circle i want to Keep.
As I don't speak German, I won't target this specifically to your SQL. But see the following quasi-code for a similar example that you should be able to apply to your own script.
SELECT C.CustomerName, O.OrderDate, O.OrderNumber
FROM CUSTOMER C
JOIN ORDERS O ON O.Customer_ID = C.Customer_ID
JOIN
(SELECT Customer_ID, OrderDate
FROM ORDERS
GROUP BY Customer_ID, OrderDate
HAVING COUNT(*) > 1) SRC
ON SRC.Customer_ID = O.Customer_ID AND SRC.OrderDate = O.OrderDate
In the script above, the last query (a subquery) would only return results where a customer had more than one order in a given day. By joining that to your main query, you would effectively produce the result asked in the OP.
Edit 1:
Regarding your comment below, I really recommend just going over your datamodel, trying to understand what's happening here, and fixing it on your own. But there is an easy - albeit hardly optimal solution to this by just using your own script above. Note, while this is not disastrous performance-wise, it's obviously not the cleanest, most effective method either. But it should work:
;WITH CTE AS (SELECT ad.Name + ' ' + ad.Vorname AS Customer,
pa.Kunde AS CustomerNr,
CONVERT(VARCHAR(10),p.datum,126) AS [Date],
(SELECT a.name + ' ' + a.Vorname AS Name FROM PRO_Mitarbeiter m LEFT JOIN ADR_Adressen a ON a.AdressNrADR=m.AdressNrADR WHERE m.MitNrPRO = l.MitNrPRO) as Employee,
p.Artikel_1 AS Article,
l.AufgabenNrCRM AS OrderNr
FROM ZUS_Therapie_Positionen p
INNER JOIN CRM_AufgabenLink l ON l.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN CRM_Aufgaben ab ON ab.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN PRO_Auftraege pa ON pa.AuftragNrPRO = ab.AuftragNrPRO
INNER JOIN ADR_Adressen ad ON ad.AdressNrADR = pa.Kunde
INNER JOIN ADR_GruppenLink gl ON gl.AdressNrADR = ad.AdressNrADR
INNER JOIN ADR_Gruppen g ON g.GruppeADR = gl.GruppeADR
WHERE l.MitNrPRO != 0
GROUP BY l.AufgabenNrCRM,ad.Name,ad.Vorname,pa.Kunde,p.datum,p.Artikel_1,l.MitNrPRO
ORDER BY pa.Kunde,p.datum,l.AufgabenNrCRM)
SELECT C.*
FROM CTE C
JOIN (Select CustomerNr, [Date]
FROM CTE B
GROUP BY CustomerNr, [Date]
HAVING COUNT(*) > 1) SRC
ON SRC.CustomerNr = C.CustomerNr AND SRC.[Date] = C.[Date]
This should work directly. But as I said, this is an ugly workaround where we're basically all but fetching the whole set twice, as opposed to just limiting the sub query to just the bare minimum of necessary tables. Your choice. :)
Tried that also and it didnt work. I also made a new query trying to Keep it so simple as possible and it doesnt work either. It still give me Single values back..
SELECT p.Datum,a.AufgabenNrCRM,auf.Kunde FROM CRM_Aufgaben a
LEFT JOIN ZUS_Therapie_Positionen p ON p.Id_Aktivitaet = a.AufgabenNrCRM
LEFT JOIN PRO_Auftraege auf ON auf.AuftragNrPRO = a.AuftragNrPRO
LEFT JOIN
(SELECT pa.Datum,au.Kunde FROM CRM_Aufgaben aa
LEFT JOIN ZUS_Therapie_Positionen pa ON pa.Id_Aktivitaet = aa.AufgabenNrCRM
LEFT JOIN PRO_Auftraege au ON au.AuftragNrPRO = aa.AuftragNrPRO
GROUP BY pa.Datum,au.Kunde
HAVING COUNT(*) > 1) SRC
ON SRC.Kunde = auf.Kunde
WHERE p.datum IS NOT NULL
GROUP BY p.Datum,a.AufgabenNrCRM,auf.Kunde
ORDER BY auf.Kunde,p.Datum

SQL -- Adding a constraint to a results row in an existing query

The following query gives me a one row result
Select Sum(Actions) From
(
Select
Count(t.Create_Dtime) As Actions
From Player_Tapjoy T
Inner Join Player_Source S
On (T.Player_Id = S.Player_Id)
Inner Join Feature_Group_Xref F
On (S.Group_Id=F.Group_Id
And F.Feature_Name ='Try BC')
Where Trunc(t.Create_Dtime) = To_Date('2012-sep-17','yyyy-mon-dd')
Union All
Select
Count(a.Create_Dtime) As Actions
From Player_Aux_Pt A
Inner Join Player_Source S
On (A.Player_Id = S.Player_Id)
Inner Join Feature_Group_Xref F
On (S.Group_Id=F.Group_Id
and f.feature_name = 'TryBC')
Where A.Site = 'AppCircle'
And Trunc(A.Create_Dtime) = To_Date('2012-sep-17','yyyy-mon-dd')
)
I now want to add in a constraint to the result where: only users that have created an account before Sep 12,2012.
In my database language: only users that have a trunc(create_dtime) < To_Date('2012-sep-12','yyyy-mon-dd') . This trunc(create_dtime) date comes from the player table.
Could I map this player table to the current table by using another inner join?
Your requirement isn't completely clear and obviously I have had to guess about your data model. I'm assuming the Player table has one row per Player_Id i.e. it is the primary key end of foreign key relationships to the tables you're querying.
I have changed the inner query so it just returns a set of rows rather than aggregations. Then I join the inline view (aliased q) with the Player table and use a COUNT() rather a SUM() to get the figure.
Select count(Player_Id) From
(
Select
T.Player_Id
From Player_Tapjoy T
Inner Join Player_Source S
On (T.Player_Id = S.Player_Id)
Inner Join Feature_Group_Xref F
On (S.Group_Id=F.Group_Id
And F.Feature_Name ='Try BC')
Where Trunc(t.Create_Dtime) = To_Date('2012-sep-17','yyyy-mon-dd')
Union All
Select
A.Player_Id
From Player_Aux_Pt A
Inner Join Player_Source S
On (A.Player_Id = S.Player_Id)
Inner Join Feature_Group_Xref F
On (S.Group_Id=F.Group_Id
and f.feature_name = 'TryBC')
Where A.Site = 'AppCircle'
And Trunc(A.Create_Dtime) = To_Date('2012-sep-17','yyyy-mon-dd')
) q
join player p
on (p.Player_Id = q.Player_Id)
where Trunc(p.Create_Dtime) < To_Date('2012-sep-12','yyyy-mon-dd')
This may not be the exact result you need, for the reasons I gave at the top, but it should point you in the right directon.

Selecting with filters

I'm developing a booking system for a clinic, so my aim is that i want to display available doctor shift which are not already reserved, the patient check the availability of a certain doctor in specific date and shift.
I have 2 tables
Booking (ID, DocID, shift_id, Date)
Shift (ID, name, DocID)
MySQL selecting query which is not working is:
SELECT Shift.ID, Shift.name, Shift.DocID
FROM Shift INNER JOIN
Booking ON Shift.ID = Booking.shift_id
WHERE (Shift.DocID = #DoctorID) AND (Booking.DocID <> #DoctorID)
AND (Booking.shift_id <> #ShiftID) AND (Booking.Date <> #VisitDate)
so please any ideas???
You could try
SELECT s.* FROM Shift
LEFT JOIN Booking b
ON s.id = b.shift_id
AND s.DocID = b.DocID
WHERE b.id IS NULL
OR b.date <> visit_date
Left join method:
SELECT s.* FROM Shift s
LEFT JOIN Booking b
ON s.id = b.shift_id
AND s.DocID = b.DocID
AND b.date = #visit_date
WHERE s.ID = #ShiftID and s.DocID = #DocID and b.id IS NULL
You could also write variants using NOT EXISTS or NOT IN clauses - the point is that you want shifts where there is no booking for that doctor, for that shift, on that day