Sorting mysql result by joined table's specic IDs - php

I have three tables
Products
id, name, desc
Flags
id, name
Product_flags
Product_id, Flag_id
Some Products have Flags linked to them while others not. I need select products and to give preferences to specific Flags in the select query.
This is my query to give preferences to flag ids 2,3,9, followed by other flags, and followed by non-flagged products ..
SELECT p.*, f.name flagname FROM products p
LEFT JOIN products_flags pf ON pf.product_id=p.id
LEFT JOIN flags f ON f.id = pf.flag_id
ORDER BY f.id=2, f.id=3, f.id=9, f.id, p.name
This sort order is not valid. How do I get it right?
Thanks

It's a strange request, but I think you might be able to get around it with a case statement in your order by clause like this:
SELECT
p.*, f.name flagname
FROM products p
LEFT JOIN products_flags pf ON pf.product_id=p.id
LEFT JOIN flags f ON f.id = pf.flag_id
ORDER BY
case
when f.id=2 then f.id-10
when f.id=3 then f.id-10
when f.id=9 then f.id-10
default f.id
end,
p.name
Edit: A column to order by might be a good idea when you want "funky" ordering. As for the case statement, what it does is returns a value to sort by but does so in this manner - sort of like an if statement:
if id=2 then treat it like -8
if id=3 then treat it like -7
if id=3 then treat it like -1
otherwise just use whatever is in id

Related

Left join and count in same query return incorrect result

The problem is that if there is 0 comment or 1 comment the count shows 1 while the rest is working well means that 2, 3, etc working fine.
$sql = "SELECT blog.*,count(blog.id) as Total FROM blog left JOIN comment on comment.id = blog.id GROUP BY date desc";
Your query should look like this:
SELECT b.date, count(c.id) as Total
FROM blog b LEFT JOIN
comment c
ON c.id = b.id
GROUP BY b.date DESC;
This assumes that date comes from blog (which should be the case if your current query is working). The difference is that you are counting from the second table, not the first.
This does not use * for columns from blog. That is usually a very, very bad idea when using GROUP BY. The best practice (enforced by almost all SQL engines) is to only include unaggregated columns in the SELECT when they are in the GROUP BY.
Note: It seems very awkward that the same column id is used for the JOIN between two very different entities (blogs and comments).
i just change to count(comment.id) from count(blog.id)

Can I replace the output value from one table with the value from another table on match?

I have two tables for an example: Posts and Categories. Posts are assigned a category, but by an ID number. When grabbing my posts, I would like to perform a LEFT JOIN and get the name of the category associated with that post, then switch the output - not the actual table content - to include the name directly in place of the value. So far, this is what I have, and I know it works to a point up to the LEFT JOIN, but the replacing values is where I get confused, though I believe it is possible
SELECT * FROM nve_multi_posts
LEFT JOIN nve_categories
SELECT
CASE
WHEN nve_multi_posts.category = nve_categories.id
THEN
nve_multi_posts.category = nve_categories.name
END
ON nve_multi_posts.category = nve_categories.id
What am I messing up?
Just that simple:
SELECT p.*, c.*
FROM nve_multi_posts p
LEFT JOIN nve_categories c
ON p.category = c.id
Or do you want some kind of UPDATE query to chenge data stored in nve_multi_posts table?
If you just need named column returned from the query you can just alias every column you need like:
SELECT p.id as post _id,
p.category as category_id,
c.name as category
FROM nve_multi_posts p
LEFT JOIN nve_categories c
ON p.category = c.id

how can i select these in mysql

Imagine that there are two tables called: Customers, Orders.
In Customers we have rows:
id=1 name=Alex key=12
id=2 name=Bob key=13
and in the Orders we have:
id=1 device=phone status=ordered key=12
id=2 device=phone status=delivered key=12
id=3 device=memory status=ordered key=13
id=4 device=memory status=returned key=13
Now I want it to choose the last one for each one of them in the Customers from Orders. Like it should choose Alex's information and the last row that is inserted for him in the Orders table.
How can I make a query for this?
You can do this with aggregation and a join:
select o.*
from customers c left join
orders o
on c.key = o.key left join
(select o.key, max(id) as maxid
from orders o
group by o.key
) ok
on o.id = oo.id;
The aggregation gets the latest value.
Note that key is a reserved word in MySQL (see here). That makes it a lousy column name, so you should change it.
Sounds like you're looking for the group-wise (key) maximum (id) as explained at https://dev.mysql.com/doc/refman/5.6/en/example-maximum-column-group-row.html
I prefer (for no good reason) the LEFT JOIN variant over the uncorrelated sub-query.
Here is a way you can do it
select
c.*,
o.id,
o.device,
o.status
from customer c
join orders o on o.`key` = c.`key`
join (
select max(id) as id,`key` from orders
group by `key`
)o1 on o1.id=o.id
http://www.sqlfiddle.com/#!9/96885/2

MYSQL Join with Null value returned

I have a query thats joining two table, using the GROUP_CONCAT to get a comma separated list which is then being mapped to an array in an object
SQL:
$sql = "SELECT *,
GROUP_CONCAT(climb_attributes.attribute_id) as climb_attributes
FROM climbs
LEFT JOIN climb_attributes ON
(climbs.id = climb_attributes.climb_id)
GROUP BY climb_id
ORDER BY climbs.id";
PHP
$all_climb_profiles[$climb->id]->attributes = explode(",", $climb->climb_attributes);
Nearly working perfectly, except I currently only get back results IF the climb_attributes table contains the climb id. Essentially a climb can still exist even if it doesn't have any attributes, but at the moment it has to have an attribute to be returned in the results.
I also need to join it to another table to get the attribute name for the attribute id...if you can help with that as well that would be great, I'm hoping I can figure that out though.
First, you should not be using * to select from all tables when using group by. You can safely take all the columns from the climb table.
The problem is that you are aggregating on a column in the second table, rather than the first. And, it is NULL if there is no match. So, a better query is:
SELECT c.*, GROUP_CONCAT(ca.attribute_id) as climb_attributes
FROM climbs c LEFT JOIN
climb_attributes ca
ON c.id = ca.climb_id
GROUP BY c.id
ORDER BY c.id;
EDIT:
If you want to list the strings, then something like this should work:
SELECT c.*, GROUP_CONCAT(a.name) as climb_attributes
FROM climbs c LEFT JOIN
climb_attributes ca
ON c.id = ca.climb_id LEFT JOIN
attributes a
ON ca.attribute_id = c.id
GROUP BY c.id
ORDER BY c.id

PHP SQL: Matching corresponding Data between 2 tables, without Filtering out Data in 1st Table

I have 2 tables. For simplicities sake 'u' has the following columns
userid
divisionid
'd' has the following:
divisionid
name
I did not create this table, otherwise I would not have this problem. u.DIVISION can be NULL. d.DIVISION cannot.
Running the following creates the appropriate data, but it also filters out every single userid that has NULL for it's divisionid. Is there anyway to still show all the userid's regardless of their divisionid and if the divisionid is not null, to then display the name of the division?
"SELECT userid, d.NAME
FROM u,d
WHERE u.divisionid = d.divisionid
ORDER BY userid"
Use an outer join:
SELECT userid, d.NAME
FROM u
LEFT OUTER JOIN division d
ON u.divisionid = d.divisionid
ORDER BY userid
Using the Oracle or implied join syntax implies an INNER JOIN. An inner join eliminates records that don't meet the criteria.
An explicit join using the JOIN clause allows you to specify the type of join.
A LEFT OUTER JOIN keeps all rows in the first table, regardless if there are matching rows in the second table.
SELECT userid, d.NAME
FROM u
LEFT OUTER JOIN division d
ON d.divisionid = u.divisionid
ORDER BY userid

Categories