I would like to add some kind of "tolerance" to the following query. That means, that I can specify a value which expresses how many of the four (sub) selects return rows > 0. So if this value is 2, I only want to join these two tables. Is there a way to realize that?
SELECT distinct(user_id) FROM
(SELECT user_id FROM table1 WHERE ...) as t1
INNER JOIN
(SELECT user_id FROM table1 WHERE ...) as t2
ON t1.user_id=t2.user_id
INNER JOIN
(SELECT user_id FROM table1 WHERE ...) as t3
ON t1.user_id=t3.user_id
INNER JOIN
(SELECT user_id FROM table1 WHERE ...) as t4
ON t1.user_id=t4.user_id
EDIT:
Possible results for each sub-query could be as follows:
t1 t2 t3 t4
0 0 0
1 1 1 1
2 2 2 2
3 3
If all these sub results are joined it would result in: 1,2.
If I add a tolerance factor of 1, I want my result to be 0,1,2 as only one "0" is missing. If the factor was 2, the result would be 0,1,2,3 because two "3" and one "0" are missing. I hope this makes it clearer.
If i had understood your problem, you can add a variable in your sub-select and filter after:
SELECT distinct(user_id) FROM
(SELECT user_id, 1 as table_from FROM table1 WHERE ...) as t1
INNER JOIN
(SELECT user_id, 2 as table_from FROM table1 WHERE ...) as t2
ON t1.user_id=t2.user_id
INNER JOIN
(SELECT user_id, 3 as table_from FROM table1 WHERE ...) as t3
ON t1.user_id=t3.user_id
INNER JOIN
(SELECT user_id, 4 as table_from FROM table1 WHERE ...) as t4
ON t1.user_id=t4.user_id
WHERE table_from <= 2;
The solution was to union all sub selects and count them like follows:
SELECT distinct(user_id), sum(t) as tolerance FROM (
SELECT user_id, 1 as t FROM table1 WHERE ... GROUP BY...
UNION ALL
SELECT user_id, 1 as t FROM table1 WHERE ... GROUP BY...
UNION ALL
SELECT user_id, 1 as t FROM table1 WHERE ... GROUP BY...
UNION ALL
SELECT user_id, 1 as t FROM table1 WHERE ... GROUP BY...
) as x GROUP BY ... HAVING tolerance <= 2
Then you can specify how many sub selects should return something (here: 2).
Related
I want to get the count of cases which are there for other tale in a format of comma separated
I have a table like below
Table1
id name
1 a
2 b
3 c
4 d
5 e
6 f
Table2
id table1_ids user_id
1 1,2,3,4,5 1
2 1,2,3 2
3 1,2,3,4,5 1
4 1,2,3,4 2
When i join them, i want to display the count of table_ids in table2 like below
Expected: a-4 b-4 c-4 d-3 e-5 f-0
Getting output: a-4 b-4 c-4
I have tried query like below using laravel raw query
DB::select('select t1.name, t1.id, count(t2.id) as count
from table1 as t1
left join table2 as t2 on FIND_IN_SET(t1.id, t2.table1_ids)>0
where t2.user_id in ('1,2')
group By t1.name, t1.id');
Please suggest me how can i acheive this
table2 is outer joined but the condition table2.user_id IN (...) inside the where clause changes the query to an inner join. Move the condition from WHERE to ON clause:
select t1.name, t1.id, count(t2.id) as count
from table1 as t1
left join table2 as t2 on
find_in_set(t1.id, t2.table1_ids) > 0 and
t2.user_id in (1, 2)
group by t1.name, t1.id
SQL Fiddle
PS: WHERE 1 IN ('1,2') attempts to convert '1,2' to a number and thus matches 1.
I am probably going to hate myself for this but this could work:
select
t1.name,
t1.id,
count(t2.id) as count
from
table1 as t1
left join
table2 as t2 on
(
-- We need to account for all of the variations of finding t1.id in the comma-separated field
t2.table1_ids = t1.id or -- exactly this ID
t2.table1_ids LIKE concat( t1.id, ',%' ) or -- starts with this ID
t2.table1_ids LIKE concat( '%,', t1.id ) or -- ends with this ID
t2.table1_ids LIKE concat( '%,', t1.id, ',%' ) -- the ID is found between two commas
)
where
t2.user_id in (1,2)
group By
t1.name, t1.id
Like a commenter suggested, should avoid adding comma separated data in table2 as it's bad practice.
However, that being said, you can use Laravel's Query Builder to build up your query to be more readable and cleaner. Building upon Salman A's point on changing the WHERE to ON you can do it like this:
DB::table("table1 as t1")
->leftJoin("table2 as t2", function($join) {
$join->on(\DB::raw("find_in_set(t1.id, t2.table1_ids) > 0 and t2.user_id in (1, 2)"), \DB::raw(""), \DB::raw(""));
})
->select("t1.name", "t1.id", \DB::raw("count(t2.id) as count"))
->groupBy("t1.name", "t1.id")
->get();
I have two tables in db
1- i want to select distinct value from 2 tables
2- i want to print the number of each value
Ex: if i have on t1
t1
--------------
a
a
a
b
t2:
t2
--------------
a
b
c
the result will be:
a (4)
b (2)
c (1)
i try this but it not what i want
$sql=mysqli_query($conn,"select db_shopname from tbl_order UNION
SELECT db_shopname FROM tbl_item order by db_shopname asc")
or die(mysqli_error($conn));
$count=mysqli_num_rows($sql);
while($res=mysqli_fetch_array($sql)){
echo $res['db_shopname'];echo $count ;echo"<br/>";
}
You need UNION ALL instead of UNION. That way you merge the values from 2 tables into 1 virtual table. Then you can count the number of individual values using GROUP BY clause. Example:
select f, COUNT(f) as countf FROM
(select t1.f from t1 union all select t2.f from t2) t
GROUP BY f
SQL Fiddle
In PHP you can then use $res['countf'] to print the count
try this one :
select a.t1,count(a.t1) as cnt from(select t1 from t1 UNION all
select t2 as t1 from t2 )a group by a.t1
I have a few tables that each have their own scores for each user. I would like to create a trigger that will add up all those scores for each user and put them in a field called score in the users table.
Tables (They essentially have the same fields with a few different ones) :
Table 1 : {id, user_id, score}
Table 2 : {id, user_id, score}
Table 3 : {id, user_id, score}
users : {id, name, overall_score}
// Overall _score has a value already , so i just want to add the score fields from the other tables to this one.
To achieve this lets first write the select query and get sum of all the scores per user from the 3 given tables and this is how it could be done
select u.*, y.total from users u
left join
(
select user_id,sum(score) as total from(
select user_id, score from table_1
union all
select user_id, score from table_2
union all
select user_id, score from table_3
)x group by x.user_id
)y on y.user_id = u.id
Here is the demo http://www.sqlfiddle.com/#!9/6f936/1
Now lets convert the select to an update command and it will be as
update users u
left join
(
select user_id,sum(score) as total from(
select user_id, score from table_1
union all
select user_id, score from table_2
union all
select user_id, score from table_3
)x group by x.user_id
)y on y.user_id = u.id
set u.overall_score = coalesce(y.total,0)
here is the demo http://www.sqlfiddle.com/#!9/c6993/1
To select data from multiple tables, you can use SQL JOINS.
See the example below:
SELECT table1.score, table2.score, table3.score
FROM table1 LEFT JOIN table2
ON table1.id=table2.id LEFT JOIN table3 ON table1.id=table3.id
This code will select the score column from table1, table2, and table3 and create one row per user_id, each containing one score-column/ table (in this case 3/ row). It's almost like having a fourth table containing all the scores, and then when you fetch them in PHP, it'd be like fetching an existing row from the database.
EDIT:
To Update the users table in the same query, you could use something like this:
UPDATE `users`,
(
SELECT table1.id as tid, table1.score as t1,
table2.score as t2, table3.score as t3
FROM table1 LEFT JOIN table2 ON table1.id=table2.id
LEFT JOIN table3 ON table1.id=table3.id
) as total
SET total_score = (t1 + t2 + t3) WHERE id = tid
Each table (table1 & table2) has its own DATETIME field.
I'm trying to catch id's of the two tables and order them by their DATETIME field.
Example:
Table 1 Table 2
------------ -------------
id | datetime1 id | table1id | datetime2
------------------------ -----------------------
1 | 2014-09-21 20:31:26 1 | 2 | 2014-09-21 20:31:29
2 | 2014-09-21 20:31:27 2 | 3 | 2014-09-21 20:31:30
3 | 2014-09-21 20:31:28
Table 3
------------
id | user
------------------------
2 | phil
3 | nathalie
My output isn't ordered properly with this query:
SELECT *
FROM (
SELECT
1 AS selection,
table1.id, table1.datetime1,
table2.datetime2
table3.user
FROM Table1
LEFT OUTER JOIN table2
ON table1.id = table2.table1id
LEFT OUTER JOIN table3
ON table1.id = table3.id
UNION ALL
SELECT
2 AS selection,
table1.id, table1.datetime1,
table2.datetime2
table3.user
FROM Table1
INNER JOIN table2
ON table1.id = table2.table1id
INNER JOIN table3
ON table1.id = table3.id
) AS query
ORDER BY table1.datetime1 DESC, table2.datetime2 DESC
Desired data:
from table 2 id: 2, 1,
from table 1 id: 3, 2, 1
So: 2, 1, 3, 2, 1
////EDIT
To people who could be struggling with long and complex MySQL request, please try it in PhpmyAdmin! It will tell you the error!
////EDIT
What you really need to do is to consider your schema more carefully. Consider naming the date time columns the same and then running a query like this - http://sqlfiddle.com/#!2/a3b4c/7/0
SELECT selection, id, datetimefoo, user FROM (
SELECT
1 AS selection,
table1.id, table1.datetimefoo,
table3.user
FROM table1
LEFT OUTER JOIN table2
ON table1.id = table2.table1id
LEFT OUTER JOIN table3
ON table1.id = table3.id
UNION
SELECT
2 AS selection,
table1.id, table1.datetimefoo,
table3.user
FROM table1
INNER JOIN table2
ON table1.id = table2.table1id
INNER JOIN table3
ON table1.id = table3.id
) AS T2
ORDER BY datetimefoo DESC
In the SQL fiddle this produces the results closer to what you're looking for. I am still not sure why you need the INNER JOINS on the second query though - there is nothing that you're doing here whcih requires them.
Here is another method that does not require a changing of the column names, but requires an alias for the sortable columns - http://sqlfiddle.com/#!2/ec4bc/3/0
SELECT * FROM (
SELECT
1 AS selection,
table1.id, table1.datetimefoo AS sort_date, -- alias on first table's date
table2.datetimebar,
table3.user
FROM table1
LEFT OUTER JOIN table2
ON table1.id = table2.table1id
LEFT OUTER JOIN table3
ON table1.id = table3.id
UNION
SELECT
2 AS selection,
table1.id, table1.datetimefoo,
table2.datetimebar AS sort_date, -- alias on second table's date
table3.user
FROM table1
INNER JOIN table2
ON table1.id = table2.table1id
INNER JOIN table3
ON table1.id = table3.id
) AS T2
ORDER BY sort_date DESC
I believe you are over-complicating a rather straight-forward task:
SELECT *
FROM (
SELECT 1 AS selection, table1.id as id, table1.datetime1 as date FROM Table1
UNION ALL
SELECT 2 AS selection, table2.id as id, table2.datetime2 as date FROM Table2
) AS query
ORDER BY date DESC
I have 3 tables.
table1
id, thing_id
table_index
id
table_index_info
table_index_id, table1_id
table_index_info contains a history of table_index. This history can refer to table1, possibly many times or 0 times.
I need to run a query that returns all rows in table1 with a specific thing_id.
It also needs to count how many rows in table_index that have at least 1 table_index_info linking to table1.
Here's my query:
SELECT table1.*,
(SELECT COUNT(i.id)
FROM table_index i
WHERE EXISTS (SELECT 0
FROM table_index_info h
WHERE h.table1_id = table1.id
AND h.table_index_id = i.id)
) AS indexCount
FROM table1
WHERE table1.thing_id= $thingId
Is this the best/correct way to do this?
I would use a JOIN instead of EXISTS in this case.
SELECT table1.*,
( SELECT COUNT(i.id)
FROM table_index i
INNER JOIN table_index_info h ON h.table_index_id = i.id
WHERE h.table1_id = table1.id
) AS indexCount
FROM table1
WHERE table1.thing_id = $thingId