I am try to get a count of all missing translations and getting really lost in how to do it.
Tables:
languages (language_id, name)
products (product_id)
product_translations (product_id, language_id, name)
The admin are getting very lazy and I want to be able to show them a count of how many translations are missing.
I guess a very simple was of doing this would be to just get the total (languages->count * products->count) but I wanted to return a count for each product separately.
To do such a query, start with a driver table (subquery) that has all combinations. Then remove the ones that have translations:
select driver.*
from (select distinct l.language_id, p.product_id
from languages l cross join
products p
) driver left outer join
translations t
on t.language_id = driver.language_id and
t.product_id = driver.product_id
where t.language_id is null;
This uses a left outer join, which keeps everything in the driver table. If there is no match, then the columns in translations will be NULL -- the where clause keeps only these.
The distinct may not be necessary in the subquery, if the values in each table are unique.
As a note: the above is my preferred way to write the query, because I think it is the clearest in intent. But, MySQL actually materializes the subquery. So the following is more efficient, if the columns are unique in the two reference tables:
select l.*, p.*
from languages l cross join
products p left outer join
translations t
on t.language_id = l.language_id and
t.product_id = p.product_id
where t.language_id is null;
Related
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
I have product details in tne table, say products, categories and brand names in different tables say categories and brand. And I want to join these in a query. The query I use is,
$sql = "
SELECT p.pid
, p.name
, p.slug
, p.category
, c.name
, p.brand
, b.name
FROM products p
JOIN categories c
ON c.sno = p.category
JOIN brand
ON b.sno = p.brand
WHERE p.sku=?
";
This query does not return any rows. However there are data in products, categories and brand tables.
Is there any logic failure in my query?
Products table
Categories table
Brand table
This is a bit long for a comment.
For the data that you have shown, your query should work. I would start by removing the where clause and running:
SELECT products.pid, products.name, products.slug, products.category, categories.name, products.brand, brand.name
FROM `products`
INNER JOIN `categories` on products.category = categories.sno
INNER JOIN `brand` on products.brand = brand.sno ;
(You should run this directly on the database; if there is a lot of data, just throw in a limit 100 to see if you get anything.)
If this doesn't return anything, then you have a problem with the joins. Look at the types of the fields. Are they the same? If not, fix the data structure. If they are characters, check for leading spaces and hidden characters.
If that query returns what you expect, the the problem is matching the skus. The most likely problem is the assignment of the value in php. Check that this is really doing what you want. Once again, check for leading spaces in the sku column and in the value. If this is the problem, you can use trim() to fix the problem.
I have three different SQL tables I need to join:
table "internet" with columns id|type|status
table "type_list" with columns id|type_name
table "status_list" with columns id|status_name
I want to output text from the two other tables (type_list, status_list) but not values as numbers which currently I have in table "internet".
I also don't want to make lazy programming - PHP array to make ID's equal to something like
$type_list = array("1"=>"VDSL2","2"=>"ADSL");
$status_list = array("1"=>"Pending","2"=>"Active");
because the text is already in the tables, i just dont know how to join them and output the text as query combined together in one query.
Use JOIN
SELECT i.id, type_name, status_name
FROM internet i
LEFT OUTER JOIN type_list t ON t.id = i.type
LEFT OUTER JOIN status_list s ON s.id= i.status
Read the MySQL doc for more informations.
Just write the select with the fields you want.
select internet.id,type_name,status_name from internet
inner join type_list
on type_list.id=internet.id
inner join status_list
on status_list.id=internet.id
For this you need a LEFT JOIN, like so:
SELECT i.id, t.type_name, s.status_name
FROM internet AS i
LEFT JOIN type_list AS t ON t.id = i.id
LEFT JOIN status_list AS s ON s.id= i.id
From your question, it is unclear what field you would like to join the queries on. In the above example, the queries are joined on the id field.
Please also note that the AS is not actually necessary, I have just put it in there to make it clear what is going on
I have two tables: 'posts' and 'users' every post has a 'ref_id' column to get the user id who posted it.
Now, I am getting posts this way:
$this->db->query("SELECT * FROM posts WHERE time > '$timeLimit' LIMIT 50");
I can't understand how to join every result to get the poster related data as well. What I am doing right now is basically a loop inside a loop, where foreach of the result, get their user info. But it is pretty obvious that this is very wrong,
Apparently I need to start using joins, but how does one do it? this should be a really simple example to work with, I suppose.
Any help? Thank you.
SELECT posts.*, users.*
FROM posts
INNER JOIN users
ON posts.posted_by = users.id;
Like this:
SELECT
posts.*,,
users.Username
FROM posts
INNER JOIN users ON posts.ref_id = users.user_id;
Explanation:
To JOIN to any tables with each others, there are two things; the JOIN type and the join condition. There are three main types of join:
INNER JOIN, only the rows that match the join condition will be returned from the two tables no more rows. But:
LEFT OUTER JOIN, when you join two tables you will have one on the left of the join keyword and the other one will be in the right:
FROM Table1 <------------- This is the left table.
LEFT OUTER JOIN table2 .... <------------- This is the right table.
In LEFT OUTER JOIN the unmatched rows from the left table will be included in the result set.
RIGHT OUTER JOIN the unmatched rows from the right table will be included in the result set.
CROSS JOIN this will perform a Cartesian product from the two tables.
In our query, the query will reutrn all the users from the users table only if the ref_id equal to the user_id column form the posts table.
For more information and explanations:
A Visual Explanation of SQL Joins.
Another Visual Representation of SQL Joins.
Join syntax in MySQL
SELECT user.name
FROM users
INNER JOIN posts
ON posts.ref_id == user.id
AND posts.time > 50
http://www.w3schools.com/sql/sql_join_inner.asp
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