Where clause with multiple values - sql

I am new to SQL and I am using MS SQL Server Management Studio 2014. I have 3 tables called Pizza, Pizza_Topping and Topping. I want to list the pizzas that have TOPPING1 and TOPPING2 as toppings.
This is what I have came up with,
select Pizza.pizzaID, Pizza.pizzaName, Topping.toppingName
from Pizza left join Pizza_Topping on
Pizza.pizzaID = Pizza_Topping.pizzaID
left join Topping on
Topping.toppingID = Pizza_Topping.toppingID
where Topping.toppingName in ('topping1', 'topping2')
and this gives me
pizzaID pizzaName toppingName
-------- ---------------- --------------
PZ002 | PIZZA1 | TOPPING1
PZ002 | PIZZA1 | TOPPING2
PZ010 | PIZZA5 | TOPPING1
PZ010 | PIZZA5 | TOPPING2
PZ011 | PIZZA6 | TOPPING1
PZ012 | PIZZA7 | TOPPING2
I only need first four rows because last two pizzas only have one of the toppings not both.
I have tried this as well,
GROUP BY Pizza.pizzaID,Pizza.pizzaName, Topping.toppingName HAVING COUNT(toppingName) >= 2
but it didn't give the expected result. that line can be used if I am going to display only pizzaID and pizzaName but i want to display toppingName as well.
to be more clear, this what I am expecting
pizzaID pizzaName toppingName
-------- ---------------- --------------
PZ002 | PIZZA1 | TOPPING1
PZ002 | PIZZA1 | TOPPING2
PZ010 | PIZZA5 | TOPPING1
PZ010 | PIZZA5 | TOPPING2
Please tell me how to achieve this result. Thanks

You are almost correct. You need to remove ToppingName from the GROUP BY:
GROUP BY Pizza.pizzaID, Pizza.pizzaName
HAVING COUNT(toppingName) >= 2
You also need to remove it from the SELECT if it is also there:
select p.pizzaID, p.pizzaName
from Pizza p join
Pizza_Topping pt
on p.pizzaID = pt.pizzaID join
Topping t
ont.toppingID = pt.toppingID
where t.toppingName in ('topping1', 'topping2')
group by p.pizzaID, p.pizzaName
having count(*) >= 2;
Also notice two things. Because you have a condition on toppings, the left join is unnecessary. You are only looking for matches, so inner join is appropriate. The use of table aliases makes the query easier to write and to read.
This assumes that pizzas cannot have duplicate toppings. If so, then change the last condition to:
having count(distinct t.toppingName) >= 2

I think this could be done more easily if you can get the count() in your subquery and then join back all the pizzaid's that have count greater than 1 something like this:
SELECT q1.pizzaID
,q1.PizzaName
,t.ToppingName
FROM (
SELECT Pizza.pizzaID
,Pizza.pizzaName
,count(topping.ToppingName) total_count
FROM Pizza
INNER JOIN Pizza_Topping ON Pizza.pizzaID = Pizza_Topping.pizzaID
INNER JOIN Topping ON Topping.toppingID = Pizza_Topping.toppingID
GROUP BY Pizza.pizzaID
,Pizza.pizzaName
HAVING count(topping.ToppingName) > 1
) q1
INNER JOIN Pizza_Topping pt ON q1.pizzaID = pt.pizzaID
INNER JOIN Topping t ON t.toppingID = pt.toppingID
WHERE t.toppingName in ('topping1', 'topping2')

Get your result without topping name . Wrap it in a view and do an inner join with Topping table .

To include the toppings you can do the COUNT-logic using Windowed Aggregate Functions:
SELECT p.pizzaID, p.pizzaName, dt.toppingName
FROM Pizza AS p
JOIN
(
SELECT p.pizzaID, t.toppingName,
COUNT(*) OVER (PARTITION BY p.pizzaID) AS cnt -- number of matching toppings
FROM Pizza_Topping AS pt
JOIN Topping AS t
ON t.toppingID = pt.toppingID
WHERE t.toppingName IN ('topping1', 'topping2')
) AS dt
ON p.pizzaID = dt.pizzaID
WHERE cnt = 2 -- number of searched toppings

You have to join to the pizza_topping and topping tables twice.
select yourfields
from pizza join pizza_topping pt1 on pizza.pizzaID = pt1.pizzaID
join topping t1 on pt1.toppingID = t1.toppingId
join pizza_topping pt2 on pizza.pizzaID = pt2.pizzaID
join topping t2 on pt2.toppingID = t2.toppingId
where t1.toppingName = 'topping1'
and t2.toppingName = 'topping2'

You can solve this problem by using group by statement restricted to Pizza Id. Please refer below query.
select Pizza.pizzaID, Pizza.pizzaName, Pizza_Toppings.Remark
from Pizza join Pizza_Toppings on
Pizza.pizzaID = Pizza_Toppings.pizzaID
join Toppings on
Toppings.toppingID = Pizza_Toppings.toppingID
where Pizza.PizzaId in (
select Pizza.PizzaID
from Pizza join Pizza_Toppings on
Pizza.pizzaID = Pizza_Toppings.pizzaID
join Toppings on
Toppings.toppingID = Pizza_Toppings.toppingID
where Toppings.TopingName in ('topping1', 'topping2')
group by pizza.PizzaId
having count(Pizza.PizzaId ) > 1)
Please let me know if this does not work for you.

Related

To join four table in mssql

MaingroupTable
MubGroupCodeid MainName maincode
1 Health 098
2 Social 078
SubGroup Table
SubGroupCodeid SubName subcode
1 Nursing 211
2 Civics 224
SubandMainGroup table
subandmainid **MubGroupCodeid** **subgroupcodeid**
1 1 1
2 2 2
Student Table
studid studname **subandmainid** (foriegn key of **subandmain group** table)
1 Alex 1
2 siraj 2
then I want to join and concatinate studname-maingroupcode-subgroupcode to get output like below
Alex-098-211
siraj-078-224
This will get you started and explain the joins. You'll probably also want to do some casting for the maincode and subcode, but since it's not 100% clear they aren't already varchar values I left that out.
SELECT s.studname + '-' + m.maincode + '-' + s.subcode
FROM Student s
INNER JOIN SubandMainGroup smg on smg.subandmainid = s.subandmainid
INNER JOIN MainGroup m on m.mubgroupcodeid = smg.mubgroupcodeid
INNER JOIN SubGroup s on s.subgroupcodeid = smg.subgroupcodeid
use join and concat all the required column by using ||
select s.studname ||'-'||subG.subcode ||'-' M.maincode
from
Student s join SubandMainGroup subM on s.subandmainid=subM.subandmainid
join SubGroup subG on subG.SubGroupCodeid=subM.subgroupcodeid
join MaingroupTable M on M.MubGroupCodeid=subM.MubGroupCodeid
Use the below query to solve the problem.
select stu.studname + '-'+mgrp.maincode +'-'+sgrp.subcode from Student_ stu
join Maingroup mgrp on stu.studid=mgrp.MubGroupCodeid
join SubGroup sgrp on sgrp.SubGroupCodeid=stu.studid

How to conditionally join two tables

I have two tables which I need to join depending upon their values.
TABLE coursemat
+-----+--------+----------+
| txt | price | material |
+-----+--------+----------+
Table coprices
+--------+----------+
| price | material |
+--------+----------+
They are connected by the material key.
If I search coursemat.material and find that coprices.material is equal, then I must use coprices.price instead of the coursemat.price.
This is what I have so far:
SELECT coursemat.txt, coursemat.price, coursemat.material, coprices, country
FROM coursemat
JOIN corprices ON coursemat.material = coprices.material;
But this isn't quite getting what I want.
Essentially, I want to use coursemat.price if coprices.price does not exist for the same material and coprices.material does exist, then I want to use coprices.price instead of coursemat.price.
If I understand what you want correctly you can use a left join and the IFNULL statement:
SELECT
coursemat.txt,
IFNULL(coprices.price, coursemat.price),
coursemat.material,
coprices.country
FROM
coursemat
LEFT JOIN
corprices
ON coursemat.material = coprices.material;
Another option is COALESCE:
SELECT cm.txt, cm.material, COALESCE(cp.price, cm.price) AS price
FROM coursemat cm
LEFT JOIN corprices cp ON cm.material = cp.material;
Finally, you could also use a CASE statement:
SELECT cm.txt, cm.material,
CASE WHEN cp.price IS NOT NULL THEN cp.price ELSE cm.price END AS price
FROM coursemat cm
LEFT JOIN corprices cp ON cm.material = cp.material;

SELF-JOIN discarding true CROSS JOIN rows

I have the following query;
What I get is tickets information. I use self-join to obtain the requester and the assignee in the same row:
SELECT z.id AS TICKET, z.name AS Subject, reqs.name AS Requester, techs.name AS Assignee,
e.name AS Entity,DATE_FORMAT(tt.date,'%y%-%m%-%d') AS DATE,
DATE_FORMAT(tt.date,'%T') AS HOUR,
CASE WHEN z.priority = 6 THEN 'Mayor' WHEN z.priority = 5 THEN 'Muy urgente' WHEN z.priority = 4 THEN 'Urgente'WHEN z.priority = 3 THEN 'Mediana' WHEN z.priority = 2 THEN 'Baja' WHEN z.priority =1 THEN 'Muy baja' END AS Priority,
c.name AS Category, i.name AS Department
FROM glpi_tickets_users tureq
JOIN glpi_tickets_users tutech ON tureq.tickets_id = tutech.tickets_id
JOIN glpi_users AS reqs ON tureq.users_id = reqs.id
JOIN glpi_users AS techs ON tutech.users_id = techs.id
JOIN glpi_tickets z ON z.id = tureq.tickets_id
LEFT OUTER JOIN glpi_tickettasks tt ON z.id = tt.tickets_id
LEFT JOIN glpi_itilcategories i ON z.itilcategories_id = i.id
LEFT JOIN glpi_usercategories c ON c.id = reqs.usercategories_id
INNER JOIN glpi_entities e ON z.entities_id = e.id
WHERE (tureq.id < tutech.id AND tureq.type < tutech.type) OR
(tureq.id < tutech.id AND tureq.users_id = tutech.users_id) OR
(tureq.id = tutech.id AND tureq.users_id = tutech.users_id)
The problem is that I get something like that:
1 Report jdoe jdoe Development 16-06-07 11:56:17 Mediana Software Mkt
1 Report jdoe fwilson Development 16-06-07 11:56:17 Mediana Software MKt
1 Report fwilson fwilson Development 16-06-07 11:56:17 Mediana Software Mkt
2 Task11 gwilliams gwilliams Ops 16-06-08 12:00:00 ALTA Hardware Def
3 Task12 gwilliams gwilliams Ops 16-06-08 12:01:00 ALTA Hardware Def
I don't want first and third row because is a CROSS JOIN result. Second row is OK, because jdoe is a requester and fwilson an assignee.
The problem is that sometimes requester and assignee are the same, eg: he creates a ticket for a task that himself will do. For example, 4th and 5th rows are OK.
So, how should I do to make a difference for those distinct cases, i.e.: I need to include:
tureq.id = tech.id AND req.users_id = tech.users.id
BUT NOT IF ALREADY EXISTS
tureq.id = tech.id AND req.users_id <> tech.users_id
Update
The main problem is that a user can assign to himself a ticket:
SELECT * from glpi_tickets_users WHERE type = 2 GROUP BY tickets_id HAVING COUNT(users_id)<2 limit 3;
+----+------------+----------+------+------------------+-------------------+
| id | tickets_id | users_id | type | use_notification | alternative_email |
+----+------------+----------+------+------------------+-------------------+
| 1 | 2 | 12 | 2 | 1 | NULL |
| 3 | 6 | 13 | 2 | 1 | NULL |
| 7 | 8 | 14 | 2 | 1 | NULL |
+----+------------+----------+------+------------------+-------------------+
Update 2:
It was a human mistake. The problem was really not about self-assigned tickets. Rather it was either that some tickets had not Requester or had Requester but still had not any resolver assigned.
I've found
As there are always the two types per ticket you are interested in, you can simply select the according records, so as to get requester and assignee per ticket.
select
t.id as ticket,
t.name as subject,
requester.name as requester,
assignee.name as assignee,
e.name as entity,
date_format(tt.date,'%y%-%m%-%d') as date,
date_format(tt.date,'%T') as hour,
case t.priority
when 6 then 'Mayor'
when 5 then 'Muy urgente'
when 4 then 'Urgente'
when 3 then 'Mediana'
when 2 then 'Baja'
when 1 then 'Muy baja'
end as priority,
uc.name as category,
ic.name as department
from glpi_tickets t
join glpi_entities e on e.id = t.entities_id
join
(
select tu.tickets_id, u.name, u.usercategories_id
from glpi_tickets_users tu
join glpi_users u on u.id = users_id
where tu.type = 1
) requester on requester.tickets_id = t.id
join
(
select tu.tickets_id, u.name
from glpi_tickets_users tu
join glpi_users u on u.id = users_id
where tu.type = 2
) assignee on assignee.tickets_id = t.id
left join glpi_itilcategories ic on ic.id = t.itilcategories_id
left join glpi_usercategories uc on uc.id = requester.usercategories_id;
left outer join glpi_tickettasks tt on tt.tickets_id = t.id
The only thing I wonder is: There can be several ticket tasks per ticket. So what do you want to do then? Have one line per ticket task in your results? This is what the query does. Only, it looks queer that your result rows don't contain any information on the tasks except for the dates, so you may have many, many lines with the same data, only with different dates. So maybe, you'd rather want the first or last date per ticket. To get the last date per ticket, you'd replace the last line in the query with:
left outer join
(
select tickets_id, max(date) as date
from glpi_tickettasks
group by tickets_id
) tt on tt.tickets_id = t.id
And you probably want to add an ORDER BY clause.
you need to add more qualifiers to your joins for example
JOIN glpi_tickets_users tutech ON tureq.tickets_id = tutech.tickets_id and tutech.type = 2

Combine results of two different records in one

I have an SQL data stored in a single table but with different type and I want to combine the result in one liner show in the example below. Anyone can give suggestion to this SQL query?
My SQL query to get this results:
SELECT NumValue, Label, Type
FROM (CustomPollerStatusTable
INNER JOIN CustomPollers ON (CustomPollerStatusTable.PollerID =
CustomPollers.CustomPollerID))
INNER JOIN Nodes ON (CustomPollerStatusTable.NodeID = Nodes.NodeID)
WHERE ((Nodes.Caption = 'fqdn') AND
(CustomPollers.Type = 'Student Info') AND
(CustomPollerStatusTable.NumValue > 89) AND
(NOT (CustomPollerStatusTable.Label LIKE '%.snapshot%')) AND
(NOT (CustomPollerStatusTable.Label LIKE '%aggr%')) AND
(NOT (CustomPollerStatusTable.Label = '/vol/scratch/'))
)
====================================
NumValue | Label | Type
====================================
90 | Student 1 | Student Info
10 | Student 1 | Student Class
====================================
The results that I would like to achieve:
==========================================================================
NumValue.Info | NumValue.Class | Label | Type.Info | Type.Class
==========================================================================
90 | 10 | Student 1 | Student Info | Student Class
==========================================================================
This should do it. Slightly different from nrathaus' answer. Obviously you can use as to change the column names to whatever you want.
select
s1.NumValue,
s2.NumValue,
s1.Label,
s1.Type,
s2.Type
from Student s1 inner join Student s2
on s1.Label = s2.Label
where s1.Type like '%Info'
and s2.Type like '%Class'
EDIT: Now that you have posted your select statement I think this might not work. Can you post the table structure?
EDIT2: This might work.
INSERT INTO TempTable(
NumValInfo,
Label,
TypeInfo)
SELECT
c.NumValue,
c.Label,
p.Type
FROM (CustomPollerStatusTable c INNER JOIN CustomPollers p
ON (c.PollerID = p.CustomPollerID))
INNER JOIN Nodes n
ON (c.NodeID = n.NodeID)
WHERE n.Caption = 'fqdn'
AND p.Type = 'Student Info'
AND c.NumValue > 89
AND NOT (c.Label LIKE '%.snapshot%')
AND NOT (c.Label LIKE '%aggr%')
AND NOT (c.Label = '/vol/scratch/')
AND p.Type like '%Info'
UPDATE TempTable set
NumValClass = c.NumValue,
TypeClass = p.Type
FROM (CustomPollerStatusTable c INNER JOIN CustomPollers p
ON (c.PollerID = p.CustomPollerID))
INNER JOIN Nodes n
ON (c.NodeID = n.NodeID)
INNER JOIN TempTable t
ON t.Label = c.Label
WHERE n.Caption = 'fqdn'
AND p.Type = 'Student Info'
AND c.NumValue > 89
AND NOT (c.Label LIKE '%.snapshot%')
AND NOT (c.Label LIKE '%aggr%')
AND NOT (c.Label = '/vol/scratch/')
AND p.Type like '%Class'
SELECT * FROM TempTable
I think this will do:
SELECT tblInfo.NumValue AS `NumValue.Info`,
tblClass.NumValue AS `NumValue.Class`,
Table.Label AS Label,
tblInfo.Type AS `Type.Info`,
tblClass.Type AS `Type.Class`
FROM (Table)
LEFT JOIN Table AS tblInfo ON tblInfo.Label = Table.Label ON tblInfo.Type = 'Student Info'
LEFT JOIN Table AS tblClass ON tblClass.Label = Table.Label ON tblClass.Type = 'Student Class'
GROUP BY Table.Label

Count Unique Results in T-SQL

My query is:
SELECT DISTINCT IncidentStatus.IncidentStatusName, Incident.IncidentID AS Bob
FROM Incident
INNER JOIN IncidentMember
ON Incident.IncidentID = IncidentMember.IncidentId
INNER JOIN IncidentStatus
ON Incident.IncidentStatusID = IncidentStatus.IncidentStatusID
WHERE (IncidentMember.MemberId = 6)
And the result is:
IncidentStatusName Bob
---------------------------
Closed 9267
In Progress 9251
In Progress 9289
New 7893
Resolved 7750
Required Result is:
IncidentStatusName Bob
---------------------------
Closed 1
In Progress 2
New 1
Resolved 1
Help Requested.
SELECT IncidentStatus.IncidentStatusName, COUNT(Incident.IncidentID) AS Bob
FROM Incident
INNER JOIN IncidentMember ON Incident.IncidentID = IncidentMember.IncidentId
INNER JOIN IncidentStatus ON Incident.IncidentStatusID = IncidentStatus.IncidentStatusID
WHERE (IncidentMember.MemberId = 6)
GROUP BY IncidentStatus.IncidentStatusName
Or maybe you need COUNT(DISTINCT Incident.IncidentID) (depends on your table structure)
take your PK field, Incident.IncidentID, out of the select distinct clause