I have Three tables look like below:
test_case
id project_id requirement_id
1 5 11,12
2 4 12,13
3 5 10,12
task_categories (refenced with test_case table with requirement_id)
id name
10 ten
11 eleven
12 twelve
13 thirtien
projects (refenced with test_case table with project_id)
id name
4 P1
5 P2
Now,i wanna make a query with where condition by passing parameter like project_id=5 and want the output look like below:
id project_name requirement_name
1 P2 eleven,twelve
3 P2 ten,twelve
I tried the following code in my model:
public function display($project_id) {
$sql = "
SELECT i.id as id, i.project_id as project_id, requirement_id, GROUP_CONCAT(c.name SEPARATOR '\n <br>*') as req_name, p.id as projects_id FROM test_case i, task_categories c, projects p
WHERE FIND_IN_SET(c.id, i.requirement_id) AND i.project_id = $project_id
GROUP BY i.id";
$query = $this->db->query($sql);
return $query->result();
}
Your current approach has a problem because it results in selecting non aggregate columns while using GROUP BY. Here is a query which should work:
SELECT t1.id,
COALESCE(t2.project_name, 'NA') AS project_name,
t1.req_name
FROM
(
SELECT t.id,
t.project_id,
GROUP_CONCAT(tc.name SEPARATOR '\n <br>*') AS req_name
FROM test_case t
INNER JOIN task_categories tc
ON FIND_IN_SET(tc.id, t.requirement_id) > 0
GROUP BY t.id, t.project_id
) t1
LEFT JOIN projects t2
ON t1.project_id = t2.id
In the above query, I join test_case and task_categories together in a subquery to obtain all combinations of id, project_id, and their requirements list. Then I use another LEFT JOIN to bring in the project name from the projects table.
Related
everyone!
I've got this table, where I keep categories and each translation is a new row with a different language_id.
categories_id language_id categories_name
8032 4 Dukke
8032 10 Doll
8029 10 Bike
8074 4 Bil
I would like to fetch those rows that doesn't have a translation for language_id 4 or language_id 10. So in this case, the output would be something like this:
categories_id language_id categories_name
8029 10 Bike
8074 4 Bil
The end result in frontend would be a list like this:
TRANSLATION 1 - TRANSLATION 2
Bike - [add translation]
[add translation] - Bil
UPDATE
A better solution will be to pivot the table; In case that you will have more languages you just need to add the CASE WHEN ... END statements for the new ones
SELECT * FROM (
SELECT
category_id
,MAX(CASE WHEN lang_id = 10 THEN category_name end) AS Translation_1
,MAX(CASE WHEN lang_id = 4 THEN category_name end) AS Translation_2
FROM (SELECT category_id, category_name, lang_id from tbl) t
group by category_id) t
WHERE Translation_1 is null OR Translation_2 is null
Try it here.
If there are only 2 languages, you can join the table on itself.
Something like:
SELECT
t1.ID, t1.CATEGORY_NAME, t2.CATEGORY_NAME
FROM your_table t1
LEFT JOIN your_table t2
ON t1.ID = t2.ID
WHERE t1.LANGUAGE_ID = 1
AND t2.ID IS NULL
For more languages, you would have to do something similar multiple times.
TRY THIS: It should work for you, collect the primary language id using subquery with MIN of every category id then join with the same table with same ID and min language_id of category to retrieve the primary translation which is TRANSLATION_1 then again join with same ID but not equal to language_id to retrieve TRANSLATION_2 AND check the condition if language_id IS NULL as below:
SELECT t.id,
t1.category_name AS TRANSLATION_1,
t2.category_name AS TRANSLATION_2
FROM (SELECT ID, MIN(language_id) language_id FROM test GROUP BY ID) t
LEFT JOIN test t1 ON t1.id = t.id
AND t1.language_id = t.language_id
LEFT JOIN test t2 ON t2.id = t.id
AND t2.language_id <> t.language_id
WHERE (t1.language_id IS NULL OR t2.language_id IS NULL)
OUTPUT: --IF one of language is NULL
id category_name category_name
7 Dolls NULL
You can do this by generating all possible rows with words and languages. Then remove the ones that do not exist:
select c.category_name, l.language_id
from (select distinct category_name from t) c cross join
(select distinct language_id from t) l left join
t
on t.category_name = c.category_name and t.language_id = l.language_id
where t.category_name is null;
i have a table that contains some articles with it's own ID and shared SKU key.
I've tried to make the query with a left join and using group result to take all ids returned from the query.
My data structure is like that:
id - name - sku - ...
1 - felix - cat
2 - tom - cat - ...
3 - sylvester - cat - ...
4 - red - pen - ...
5 - blue - pen - ...
I tried to use this query:
SELECT * FROM `test`
[LEFT/RIGHT/INNER] JOIN
(
SELECT GROUP_CONCAT(DISTINCT id) AS idsgroup FROM `test` WHERE (attribute_name = 'sku') GROUP BY value_name LIMIT 0, 3
) bind
ON id IN (bind.idsgroup);
this query is wrong, it return only 1 id per group instead all ids selected from concat or in LEFT JOIN case, obviously all rows.
Any suggestion workaround to achieve the right result?
EDIT:
here a fiddle with the structure:
http://sqlfiddle.com/#!9/b6747a
And the query i tried into:
SELECT * FROM `view_test`
INNER JOIN
(
SELECT GROUP_CONCAT(DISTINCT entity_id) AS idsgroup FROM `view_test` WHERE (attribute_name = 'sku') GROUP BY value_name LIMIT 0, 3
) bind
ON entity_id IN (bind.idsgroup);
As this pic show, my result lost some ids, part of the group.
EDIT 2:
after i used FIND_IN_SET() suggested by Kickstart the result is the expected:
SELECT * FROM `view_test`
INNER JOIN
(
SELECT GROUP_CONCAT(DISTINCT entity_id) AS idsgroup FROM `view_test` WHERE (attribute_name = 'sku') GROUP BY value_name LIMIT 0, 3
) bind
ON FIND_IN_SET(entity_id, bind.idsgroup);
The simple fix would appear to be to use FIND_IN_SET for the join. But this is a bit of a hack and will not be that quick.
SELECT *
FROM `view_test`
INNER JOIN
(
SELECT GROUP_CONCAT(DISTINCT entity_id) AS idsgroup
FROM `view_test`
WHERE (attribute_name = 'sku')
GROUP BY value_name
LIMIT 0, 3
) bind
ON FIND_IN_SET(entity_id, bind.idsgroup);
Further not sure why you have a LIMIT on the sub query, especially without an order clause.
Possibly better to use a sub query to just get the DISTINCT entity_id with an attribute_name of sku and join against that.
SELECT *
FROM `view_test`
INNER JOIN
(
SELECT DISTINCT entity_id
FROM `view_test`
WHERE (attribute_name = 'sku')
) bind
ON view_test.entity_id = bind.entity_id
Something like this?
SELECT t.*, group_concat(t2.id) FROM `test` t
LEFT JOIN test t2 ON t2.attribute_name = 'sku' and t.id != t2.id
group by t.id;
row, and the list of all ids that have same SKU
I want to select the rows from products table.
The products are season based.
each product row/entity contains a column named id_season
and seasons table looks like
id | season_name | active | created | modified
Season names are Year like 2016,2017,2018 ...
I want to select all the products from 2016 and 2017 which have same code
I have a simple select like
SELECT *
FROM products P
INNER JOIN seasons S ON S.id = P.id_season
WHERE S.active = 1
AND S.season_name IN ( YEAR(GETDATE()), YEAR(GETDATE()) + 1 )
but don't know how to refine it, to match the codes on products from different seasons.
Try with the below code..
;WITH cte_1
AS
(SELECT *,COUNT(p.code) OVER(partition by p.code Order by p.code) cnt
FROM products P
INNER JOIN seasons S ON S.id = P.id_season
WHERE S.active = 1
AND S.season_name IN ( YEAR(GETDATE()), YEAR(GETDATE()) + 1 )) -- or simply put IN ('2016','2017')
SELECT *
FROM cte_1
WHERE cnt>1
or you can use a subquery format as below.
SELECT *
FROM
(SELECT *,COUNT(p.code) OVER(partition by p.code Order by p.code) cnt
FROM products P
INNER JOIN seasons S ON S.id = P.id_season
WHERE S.active = 1
AND S.season_name IN ( YEAR(GETDATE()), YEAR(GETDATE()) + 1 )) t
WHERE t.nt>1
You can use inner query as follows:
SELECT * FROM products
where id_season in (Select id from seasons where
season_name IN ( YEAR(GETDATE()), YEAR(GETDATE()) + 1 ));
I want to show the conclusion of all users.
I have 3 tables.
table post
post_id(index) user_id
1 1
2 3
3 3
4 4
table photo
photo_id(index) user_id
1 2
2 4
3 1
4 1
table video
photo_id(index) user_id
1 4
2 4
3 3
4 3
and in table user
user_id(index) user_name
1 mark
2 tommy
3 john
4 james
in fact, it has more than 4 rows for every tables.
I want the result like this.
id name post photo videos
1 mark 1 2 0
2 tommy 0 1 0
3 john 2 0 2
4 james 1 1 2
5 .. .. .. ..
Code below is SQL that can work correctly but very slow, I will be true appreciated if you help me how it using LEFT JOIN for it. Thanks.
SQL
"select user.*,
(select count(*) from post where post.userid = user.userid) postCount,
(select count(*) from photo where photo.userid = user.userid) photoCount,
(select count(*) from video where video .userid = user.userid) videoCount
from user order by user.id"
(or ORDER BY postCount, photoCount or videoCount ASC or DESC as i want )
I done researched before but no any helped me.
SELECT u.user_id,
u.user_name,
COUNT(DISTINCT p.post_id) AS `postCount`,
COUNT(DISTINCT ph.photo_id) AS `photoCount`,
COUNT(DISTINCT v.video_id) AS `videoCount`
FROM user u
LEFT JOIN post p
ON p.user_id = u.user_id
LEFT JOIN photo ph
ON ph.user_id = u.user_id
LEFT JOIN video v
ON v.user_id = u.user_id
GROUP BY u.user_id
ORDER BY postCount;
Live DEMO
Your method of doing this is quite reasonable. Here is your query:
select user.*,
(select count(*) from post where post.userid = user.userid) as postCount,
(select count(*) from photo where photo.userid = user.userid) as photoCount,
(select count(*) from video where video.userid = user.userid) as videoCount
from user
order by user.id;
For this query, you want the following indexes:
post(userid)
photo(userid)
video(userid)
user(id)
You probably already have the last one, because user.id is probably the primary key of the table.
Note that a left join approach is a bad idea in this case. The three tables -- posts, photos, and videos -- are independent of each other. If a user has five of each, then joining them together would produce 125 intermediate rows. If a user has fifty of each, it would be 125,000 -- a lot of extra processing.
Your answer is probably slow as it is using a correlated sub-query i.e. the sub query is running once for each user_id (unless the optimizer is doing something smart - which shouldn't be counted on).
You could use a left outer join and count or use something temporary like:
SELECT u.user_id,
u.user_name,
ph.user_count AS 'photoCount',
p.user_count AS 'postCount',
v.user_count AS 'videoCount'
FROM user u
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM photo
GROUP BY user_id
) ph
ON ph.user_id=u.user_id
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM post
GROUP BY user_id
) p
ON p.user_id=u.user_id
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM video
GROUP BY user_id
) v
ON v.user_id=u.user_id
There are pros and cons for both (depending on indexes). Always have a look at the query plan (using EXPLAIN for MySQL).
Is it possible to add and multiply the count of different tables where the id is the same?
Imagine:
Table_1 Table_2 Table_3
id id id
1 1 1
1 2 2
2 2 3
3 2 3
3 2 3
3 3 3
So that the end result would be this table with 2 columns:
id (COUNT(Table_1.id) + 2*COUNT(Table_2.id) + 3*COUNT(Table_3.id))
1 7
2 12
3 17
I don't know if I understood you correctly but give this a try,
SELECT a.ID,
a.aa + (2 * b.bb) + (3 * c.cc)
FROM
(
SELECT ID, COUNT(*) aa
FROM table1
GROUP BY ID
) a LEFT JOIN
(
SELECT ID, COUNT(*) bb
FROM table2
GROUP BY ID
) b ON a.ID = b.ID
LEFT JOIN
(
SELECT ID, COUNT(*) cc
FROM table3
GROUP BY ID
) c ON a.ID = c.ID
SQLFiddle Demo
SELECT id, counts_1.number + 2 * counts_2.number + 3 * counts_3.number
FROM
(SELECT id, COUNT(*) AS number FROM Table_1 GROUP BY id) AS counts_1
JOIN
(SELECT id, COUNT(*) AS number FROM Table_2 GROUP BY id) AS counts_2 USING (id)
JOIN
(SELECT id, COUNT(*) AS number FROM Table_3 GROUP BY id) AS counts_3 USING (id)
Note that this solution requires that every id exists at least once in each of the tables, otherwise it will be left out of the result. Changing this would require a FULL OUTER JOIN that MySQL is incapable of. There are ways around that limitation, though.