Getting unique group by values over 4 different columns - mysql

Ok, what I'm trying to do is try and get unique values from one table that span 4 separate columns.
For example, I have this below query which works correctly on one of the columns..
SELECT
rest.cuisine1, c.name
FROM
specials
INNER JOIN restaurant AS rest ON specials.restaurantid=rest.id
INNER JOIN cuisine AS c ON rest.cuisine1=c.id
WHERE
dateend >= CURDATE()
AND
(specials.state='VIC' OR specials.state = 'ALL')
AND
specials.status = 1
AND
rest.status = 1
GROUP BY
c.id;
Now, rest.cuisine1 is one of the columns that contain the data. As expected this query returns unique values from that column only. The below being an example of what is returned:
12 Cafe
18 Asian
29 Coffee
There are 3 more columns in that table, those being:
rest.cuisine2
rest.cuisine3
rest.cuisine4
I could run the above query 4 times (one on each column) and THEN run the values through PHP to get only unique values from the 4 different result sets, however I was wanting to find out if I can get what I want all in the one query.

try this
SELECT
rest.cuisine1, c.name ,rest.cuisine2 , rest.cuisine3, rest.cuisine4
FROM
specials
INNER JOIN restaurant AS rest ON specials.restaurantid=rest.id
INNER JOIN cuisine AS c ON rest.cuisine1=c.id
INNER JOIN cuisine AS c2 ON rest.cuisine2=c2.id
INNER JOIN cuisine AS c3 ON rest.cuisine3=c3.id
INNER JOIN cuisine AS c4 ON rest.cuisine4=c4.id
WHERE
dateend >= CURDATE()
AND
(specials.state='VIC' OR specials.state = 'ALL')
AND
specials.status = 1
AND
rest.status = 1
GROUP BY
c.id;

This answer is based off of MahmoudGamal's answer he posted in a comment, which he deleted for some reason.
I used the below..
SELECT
c.id, c.name
FROM
specials
INNER JOIN restaurant AS rest ON specials.restaurantid=rest.id
INNER JOIN cuisine AS c ON c.id IN (rest.cuisine1, rest.cuisine2, rest.cuisine3, rest.cuisine4)
WHERE
dateend >= CURDATE()
AND
(specials.state='VIC' OR specials.state = 'ALL')
AND
specials.status = 1
AND
rest.status = 1
GROUP BY
c.id;

Related

Get several data from SQL query based on different conditions

I have the following code:
SELECT DISTINCT m.solde_total_client
,c.client_nom
,co.contenant_nom
FROM `mouvement` m, `client` c, `contenant` co
WHERE c.client_id = m.client_id
AND co.contenant_id = m.contenant_id
ORDER BY m.movement_date DESC
LIMIT 1;
And I get as a result one total sold of one client. But I want to get one for each contenant for each client. (But it still need to be the last one by date)
I'm getting as a result:
And I want to get several result like that such as:
Leclerc | Geobox | 50
SuperU | Box | 40
...
sold_total_client is what the client as after a shipment, there is several shipment and the sold is updated at every move, so the last one by date is the actual sold. So I have to get the last move of every contenant of every client.
You could try using a subquery for max_date group by client_id, contenant_id
SELECT
m.solde_total_client,
m.`mouvement_date`,
c.client_nom,
co.contenant_nom
FROM
`mouvement` m
INNER JOIN
(SELECT
MAX(mouvement_date) max_date, client_id, contenant_id
FROM
`mouvement`
GROUP BY
client_id, contenant_id) t ON t.client_id = m.client_id
AND m.contenant_id = t.contenant_id
AND t.max_date = m.`mouvement_date`
INNER JOIN
`client` c ON c.client_id = m.client_id
INNER JOIN
`contenant` co ON co.contenant_id = m.contenant_id
ORDER BY
m.`mouvement_date`

How do I get the MIN value from two columns along with corresponding id?

My query does return the lowest price from the two columns (price_base, price_special) but it is not returning the correct store_id that corresponds to the lowest price found.
My Query:
SELECT grocery_item.id, grocery_item.category,
grocery_category.name AS cat, grocery_item.name AS itemName,
MIN( if( grocery_price.price_special>0,
grocery_price.price_base)) AS price,
grocery_price.store_id,
grocery_store.name AS storeName
FROM grocery_item
LEFT JOIN grocery_category ON
grocery_category.id=grocery_item.category
LEFT JOIN grocery_price
ON grocery_price.item_id = grocery_item.id
LEFT JOIN grocery_store
ON grocery_store.id=grocery_price.store_id
WHERE grocery_price.selection='no'
AND buy='yes'
GROUP BY grocery_price.item_id
ORDER BY store_id, grocery_item.category, grocery_item.name
Returns this:
ID category cat itemName price store_id storeName
92 3 Bread/Bakery Arnold Bread 2.14 1 Food Lion
But the grocery_price table holds this info:
item_id price_base price_special store_id
92 4.29 2.14 9
92 3.99 0.00 1
so the store_id I need to be returned is 9 (the storeName returned would NOT then be Food Lion)
EDIT: WORKING QUERY based on Uueerdo's comments (thank you!)
SELECT minP.item_id, gi.category, gc.name AS cat,
gi.name as itemName, gp.store_id,
gs.name AS storeName, minP.price
FROM
(SELECT p.item_id, MIN(IF(p.price_special >0,
p.price_special,p.price_base)) AS price
FROM grocery_item AS i
INNER JOIN grocery_price AS p ON (i.id = p.item_id)
WHERE i.buy = 'yes'
GROUP BY p.item_id) AS minP
INNER JOIN grocery_item AS gi ON minP.item_id = gi.id
INNER JOIN grocery_category AS gc on gi.category = gc.id
LEFT JOIN grocery_price AS gp
ON minP.price = IF(gp.price_special > 0,
gp.price_special,gp.price_base)
AND gp.item_id = gi.id
INNER JOIN grocery_store AS gs ON gp.store_id = gs.id
GROUP BY gi.id
ORDER BY gs.id, gi.category,gi.name
The values returned for non-grouped, non-aggregated fields are an (effectively) random selection from the values encountered with the grouped fields' values. Most RDBMS do not even consider such a query valid, and even newer versions of MySQL default to disallowing such queries.
In cases like yours, where you need the non-grouped value(s) associated with the aggregate result (min in this case); the aggregating query must be converted into a subquery, that can be joined back to the aggregated tables to find the source row(s) that correspond to the aggregated value.
Edit: Basically, you need to look at the problem slightly differently. You're currently finding the lowest price for an item and a store that item is listed for; you need to find the lowest price for an item, and use that to find the store(s) that have the item at that price.
This gets you the lowest price for item's marked "buy":
SELECT p.item_id, MIN(IF(p.price_special > 0,p.price_special,p.price_base)) AS price
FROM grocery_item AS i
INNER JOIN grocery_price AS p ON (i.id = p.item_id)
WHERE i.buy = 'yes'
GROUP BY p.item_id
You can then take that to get the rest of the results:
SELECT minP.item_id
, gi.name
, gi.category, gc.category_name AS cat, gi.Name as itemName, gi.buy
, gp.store_id, gp.name AS storeName
, minP.price
FROM ([the query above]) AS minP
INNER JOIN grocery_item AS gi ON minP.item_id = gi.id
INNER JOIN grocery_category AS gc on gi.category = gc.grocery_category_id
/* Guessing on this join since grocery_category_id
was not qualified with it's table name */
INNER JOIN grocery_price AS gp
ON minP.price = IF(gp.price_special > 0,gp.price_special,gp.price_base)
/* Alternatively: ON minP.price IN (gp.price_special, gp.price_base)
... though this could cause false positives if the minP.price is 0
from one store's base price being "free"
*/
INNER JOIN grocery_store AS gs ON gp.store_id = gs.id
;

How do I perform this join query?

I have a table leave_form which looks like:
type id reporting_id leave_bal from_date_id leave_from to_date_id leave_to number leave_for status applied_dates_id pendays
personal 99 6 10 1023 full day 1313 full day 10 personal yes 1026 null
I have separate table for dates, so that I can refer these dates into leave_form. My leave_date table looks like:
date_id(AI) dates(UK)
1025 2016-02-18
1301 2016-02-20
1218 2016-02-16
This date_id I have inserted into from_date_id, to_date_id, applied_dates_id columns in leave_form table i.e. all dates are inserted into leave_date table and from this table I am only referring the date_id into leave_form table.
There is also a table that keeps the emp_code and emp_name. My personal table is:
id(AI) emp_code(PK) emp_name
99 K0209 Nijo
When I am trying to fetch the date for from_date_id, to_date_id, applied_dates_id column from leave_form table I don't get any values.
My query for fetching the dates is:
select g.type, a.emp_code, h.rm_id, h.rm_name, g.leave_bal, i1.dates as from_date,
g.leave_from, i2.dates as to_date, g.leave_to, g.number, g.leave_for, g.status,
i3.dates as applied_date, g.pendays
from personal a
inner join leave_form g
on a.id = g.id
inner join inform_to_rm h
on h.reporting_id = g.reporting_id
inner join leave_dates i1
on i1.dates = g.from_date_id
inner join leave_dates i2
on i2.dates = g.to_date_id
inner join leave_dates i3
on i3.dates = g.applied_dates_id
where a.emp_code = 'K0209';
It shows me result like:
type, emp_code, rm_id, rm_name, leave_bal, from_date, leave_from, to_date, leave_to, number, leave_for, status, applied_date, pendays
i.e no data gets returned when I am executing this query.
I would agree with one of the comments to the question. I would recommend referencing the date directly in the leave_form table instead of a FK to a table with dates. But back to the question. You haven't described all of your tables completely, so it is possible that there are multiple problems that I can't see, however, there is definitely one problem.
Your query joins on
inner join leave_dates i1
on i1.dates = g.from_date_id
inner join leave_dates i2
on i2.dates = g.to_date_id
inner join leave_dates i3
on i3.dates = g.applied_dates_id
This is incorrect. leave_dates.dates is the actual DATE, while the columns that you are joining on (leave_form.from_date_id, leave_form.to_date_id, leave_form.applied_dates_id) are foreign key references.
For example, 1023 does not equal 2016-02-18 so you get no match. Replacing the above query-snippet with the following would correct this particular problem.
inner join leave_dates i1
on i1.date_id = g.from_date_id
inner join leave_dates i2
on i2.date_id = g.to_date_id
inner join leave_dates i3
on i3.date_id = g.applied_dates_id

I want to go down further into query, but not sure how

MySQL Table Diagram:
My query this far:
SELECT tblcourses.CourseStandard,
tblcourses.CourseID,
tblcourses.CourseRef,
tblcourses.CourseStandard,
tblcourses.CourseName,
tblcourses.CourseDuration,
tblcourses.NQFLevel,
tblcourses.CoursePrice,
tblcoursestartdates.StartDate
FROM etcgroup.tblcoursestartdates tblcoursestartdates
INNER JOIN etcgroup.tblcourses tblcourses
ON (tblcoursestartdates.CourseID = tblcourses.CourseID)
WHERE tblcoursestartdates.StartDate >= Now()
If you look at the diagram you will see I have a 3rd table. The query above works fine. It display all the data as it should.
I want to show all the courses and their respective dates excluding those that the student is already booked for. Keep in mind that there can be 20 start dates for 1 course. This is why I am only choosing dates >= Now().
I want to make sure that a student does not get double booked. Yes I can do it afterwards. Beep student already booked BUT if I can have it now show the course dates that the student already booked then great. Any suggestions?
This is pretty straightforward. Presumably you know the StudentID you'd like to see. Do a left join to the bookings table and select the mismatches.
SELECT tblcourses.CourseStandard,
tblcourses.CourseID,
tblcourses.CourseRef,
tblcourses.CourseStandard,
tblcourses.CourseName,
tblcourses.CourseDuration,
tblcourses.NQFLevel,
tblcourses.CoursePrice,
tblcoursestartdates.StartDate
FROM etcgroup.tblcoursestartdates tblcoursestartdates
INNER JOIN etcgroup.tblcourses tblcourses
ON tblcoursestartdates.CourseID = tblcourses.CourseID
AND tblcoursestartdates.StartDate >= Now()
LEFT JOIN tblbookings
ON tblbookings.CourseId = tblcourses.CourseId
AND tblbookings.StudentId = <<<the student ID in question >>>
WHERE tblbookings.BookingID IS NULL
The trick here is the LEFT JOIN ... IS NULL pattern. It eliminates the rows where the ON condition of the LEFT JOIN hit, leaving only the ones where it missed.
Do a left join to tblBookings on courseID where the bookingID is null (there are no matches). You'll have to provide the studentID as a parameter to the query.
SELECT DISTINCT c.CourseStandard,
c.CourseID,
c.CourseRef,
c.CourseStandard,
c.CourseName,
c.CourseDuration,
c.NQFLevel,
c.CoursePrice,
d.StartDate
FROM etcgroup.tblcoursestartdates d
INNER JOIN etcgroup.tblcourses c ON d.CourseID = c.CourseID
LEFT JOIN etcgroup.tblBookings b on c.CourseID = b.CourseID and b.StudentID = #StudentID
WHERE d.StartDate >= Now() and b.bookingID is null
Use NOT EXISTS or NOT IN to find the courses a student has already booked:
SELECT
c.CourseStandard,
c.CourseID,
c.CourseRef,
c.CourseStandard,
c.CourseName,
c.CourseDuration,
c.NQFLevel,
c.CoursePrice,
csd.StartDate
FROM etcgroup.tblcourses c
INNER JOIN etcgroup.tblcoursestartdates csd ON csd.CourseID = tblcourses.CourseID
WHERE csd.StartDate >= Now()
AND c.CourseID NOT IN
(
SELECT CourseID
FROM tblbookings
WHERE StudentID = 12345
);

Update Table by Join and Group by

A Company has many Reviews which has Rating Column itself.
CompID Ratig
12 3
13 3
17 4
22 4
23 5
24 3
28 3,2
This is what I need to be set to each company by id. Now Rating In Company Column is NULL.
I've written something like this:
UPDATE Companies c
JOIN Reviews r on c.CompanyID = r.CompanyID
SET c.Rating = AVG(r.rating)
group by r.CompanyID
This should do what you want using a simple nested query, in this case probably simpler than a JOIN.
UPDATE Companies
SET Rating =
(SELECT AVG(Rating)
FROM Ratings
WHERE Companies.CompanyId = Ratings.CompId)
Simple SQLfiddle demo here.
EDIT: If you really want to use a JOIN/UPDATE FROM, it'd look something like this;
UPDATE c
SET c.Rating = r.Rating
FROM Companies c
JOIN (SELECT AVG(Rating) Rating, CompID FROM Ratings GROUP BY CompId) r
ON c.CompanyId = r.CompId
At least to me, somewhat more complicated to read, and afaik it only works on SQL Server, but here's the SQLfiddle for that too :)
UPDATE ComisionesxColaboradorxLineaPrescripciones
SET CANTIDAD_PRODUCTOS_CORE_CUMPLE = CANTIDAD
FROM #ComisionesxColaboradorxLineaPrescripciones ComisionesxColaboradorxLineaPrescripciones
INNER JOIN
(SELECT TAB_L.COD_COLAB AS COD_COLAB,TAB_L.TIPO_COLABORADOR AS TIPO_COLABORADOR, COUNT(TAB_P.COD_SEG) AS CANTIDAD
FROM #ComisionesxColaboradorxLineaPrescripciones TAB_L
INNER JOIN #ComisionesxColaboradorxLineaxProductoPrescripciones TAB_P
ON TAB_L.COD_COLAB=TAB_P.COD_COLAB AND
TAB_L.TIPO_COLABORADOR=TAB_P.TIPO_COLABORADOR
GROUP BY TAB_L.COD_COLAB,TAB_L.TIPO_COLABORADOR
) AGRUPADO
ON ComisionesxColaboradorxLineaPrescripciones.COD_COLAB = AGRUPADO.COD_COLAB AND
ComisionesxColaboradorxLineaPrescripciones.TIPO_COLABORADOR = AGRUPADO.TIPO_COLABORADOR