MySql joining table with condition [duplicate] - mysql

I have a table id1, id2, type. type is an enumerated value containing a name of another table.
I'd like to preform a join with the name of the table of type.
For example:
switch($type)
case 'table1':
join table1;
break;
case 'table2':
join table2;
break;
How can I achieve this?

You can't do it directly like that... you can do something like this though (not very pretty...):
SELECT
t.id,
t.type,
t2.id AS id2,
t3.id AS id3
FROM t
LEFT JOIN t2 ON t2.id = t.id AND t.type = 't2'
LEFT JOIN t3 ON t3.id = t.id AND t.type = 't3'

ugly way:
Table Types, T1, T2:
SELECT ... FROM Types, T1 , where Types.ID=T1.Types_ID AND Types.TYPE='TABLE1'
UNION
SELECT ... FROM Types, T2 , where Types.ID=T2.Types_ID AND Types.TYPE='TABLE2'

In addition to previous answer:
You can combine the two left joins results by using IF statement:
IF(t.type= 't2', t2.id, t3.id) as type_id
You can see another mysql conditional joins example at mysqldiary.com

I needed to implement such a thing with Laravel Query Builder. I was preparing a library and shouldn't rebuild the whole query, I wanted to utilize Eloquent as much as possible so I could only add a join to the query. This could be a little closer to what you want but also a lot uglier than you would expect:
SELECT
`comments`.*,
`commentable`.`created_at` AS `commentable_created_at`
FROM
`comments`
LEFT JOIN ((
SELECT
*,
CONCAT('post_', `id`) AS `morphed_key`
FROM
`posts`)
UNION (
SELECT
*,
CONCAT('image_', `id`) AS `morphed_key`
FROM
`images`)) AS `commentable` ON
CONCAT(`comments`.`commentable_type`, '_', `comments`.`commentable_id`)= `commentable`.`morphed_key`
The point of using this way is that you are now able to add WHERE clauses like WHERE commentable.owner_id=?

Related

MySQL UNION returns ids that don't exist

I have a table t with 900 ids, 1-900. For the purpose of my task, I need to do something like (I think there is no meaning in try to reason behind this type of query, as it's something I'm experimenting on):
The id is NOT unique (as it is somewhat of foreign key let's say)!
SELECT DISTINCT(t5.id) FROM (
SELECT DISTINCT(t1.id) FROM t t1 WHERE {...}
UNION SELECT DISTINCT(t2.id) FROM (
SELECT DISTINCT(t0.id) FROM t t0 WHERE {...}) as t2
INNER JOIN t t3 ON t2.id=t3.id WHERE{...}
UNION SELECT DISTINCT(t3.id) FROM t t4 WHERE {...})
t5 ORDER BY t5.id
The problem is that the query, returns ids that are far from the 900 existing ones. The go all they way up to more than 10.000-20.000. Please help me provide you all the necessary information needed.
I'm not sure, but perhaps you need to add as id in the second select field, like this:
SELECT DISTINCT(id) FROM ( SELECT DISTINCT(t1.id) **as id** FROM t t1 WHERE {...} UNION SELECT DISTINCT(t2.id) FROM t t2 WHERE {...} INNER JOIN t t3 ON t2.id=t3.id WHERE{...} UNION SELECT DISTINCT(t3.id) FROM t t4 WHERE {...}) t5 ORDER BY t5.id

sql get column from the 'EXISTS' statemenent

i have the following sql query
SELECT Store.*
FROM Store
WHERE EXISTS (
SELECT Contest.StoreID .....)
OR EXISTS (
SELECT Discount.StoreID .....)
my problem is that i want to include to the results some columns from the Contest and the Discount arrays. If I join them on the FROM it works but is there a way to get the values from the EXISTS ? something like this
SELECT Store.*, t1.something, t2.somethingElse
FROM Store
WHERE EXISTS (
SELECT Contest.StoreID .....) t1
OR EXISTS (
SELECT Discount.StoreID .....) t2
No, its not possible to select from the WHERE clause, think about it, this clause if for filtering.
There are two ways for selecting data from different tables together, a sub query or with a join.
Here is a JOIN example :
SELECT s.*, t1.something, t2.somethingElse
FROM Store s
LEFT OUTER JOIN Contest t1 ON(...)
LEFT OUTER JOIN Discount t2 ON(...)
WHERE t1.<column> is not null OR t2.<column> is not null
This will do the same as your query with the EXISTS() , and will probably have similar performance.
Can also be done we a correlated sub query :
SELECT * FROM (
SELECT s.*,
(SELECT t1.something FROM contest t1 WHERE t1.<col> = s.<col>) as col1,
(SELECT t1.something FROM contest t1 WHERE t1.<col> = s.<col>) as col2,
FROM Store s) t
WHERE t.col1 is not null or t.col2 is not null

Sum the same value with different condition

Ok, the title is cryptic but I don't know how to sintetize it better.
I have a series of expensive similar SELECT SUM queries that must be executed in sequence.
Example:
SELECT SUM(t2.Field)
FROM Table1 AS t1
INNER JOIN (
SELECT Field FROM Table2
WHERE [list of where]
) AS t2 ON ti.ExtKey = t2.Key
WHERE t1.TheValue = 'Orange'
SELECT SUM(t2.Field)
FROM Table1 AS t1
INNER JOIN (
SELECT Field FROM Table2
WHERE [list of where]
) AS t2 ON ti.ExtKey = t2.Key
WHERE t1.TheValue = 'Apple'
And so on.
I've used the nested inner join because after some test it resulted faster than a plain Join.
The rows selected for Table2 are always the same, or at least the same for session.
There's a way to group all the queries in one to speed up the execution?
I was thinking about using a material view, but this would complicate very much the design and maintenance.
I am no sure about your goal. I have a guess for you:
http://sqlfiddle.com/#!9/af66e/2
http://sqlfiddle.com/#!9/af66e/1
SELECT
SUM(IF(t1.TheValue = 'Orange',t2.Field,0)) as oranges,
SUM(IF(t1.TheValue = 'Apple',t2.Field,0)) as apples
FROM Table1 AS t1
INNER JOIN (
SELECT Field, `key` FROM Table2
) AS t2 ON t1.ExtKey = t2.`key`
# GROUP BY t1.extkey uncomment if you need it
If you can provide raw data sample and expected result that would help a lot.
I think you want a group by:
SELECT t1.TheValue, SUM(t2.Field)
FROM Table1 t1 INNER JOIN
(SELECT Field
FROM Table2
WHERE [list of where]
) t2
ON t1.ExtKey = t2.Key
GROUP BY t1.theValue;
Note that your query doesn't quite make sense, because t2 doesn't have a column called key. I assume this is an oversight in the question.
If you want to limit it to particular values, then use a WHERE clause before the GROUP BY:
WHERE t1.TheValue IN ('Apple', 'Orange', 'Pear')

Looking for an alternative SQL command to find the same values in two tables

I am using this command to find the same values in two tables when the tables have 100-200 records. But When the tables have 100000-20000 records, the sql manager, browsers, shortly the computer is freesing.
Is there any alternative command for this?
SELECT
distinct
names
FROM
table1
WHERE
names in (SELECT names FROM table2)
Try with join
SELECT distinct t1.names
FROM table1 t1
join table2 t2 on t2.names = t1.names
Use EXISTS:
SELECT distinct t1.names
FROM Table1 t1
WHERE EXISTS(
SELECT 1 FROM tabl2 t2 WHERE t2.names=t1.names
)
SELECT DISTINCT t1.names
FROM table1 t1
INNER JOIN table2 t2 on t1.names=t2.names
The use of the INNER JOIN ensures that there are only exact matches returned from both tables. It should be relatively quick, but indexes may be required over the long term, especially if you're using them for other JOINs and GROUP BYs etc.
a simple join will also do it.
make sure the column is indexed.
select distinct t1.names
from table1 t1, table2 t2
where t1.names = t2.names
Show names from both tables where there is a match
SELECT names
FROM table1
UNION ALL
SELECT names
FROM table2
This query will return duplicated values if there are any. If you only want distinct values then try this but note that there will be an impact on performance
SELECT names
FROM table1
UNION
SELECT names
FROM table2
SELECT table1.names
FROM table1
INNER JOIn table2
ON table1.names = table2.names
Group By table1.names

conditional join in mysql

I have a table id1, id2, type. type is an enumerated value containing a name of another table.
I'd like to preform a join with the name of the table of type.
For example:
switch($type)
case 'table1':
join table1;
break;
case 'table2':
join table2;
break;
How can I achieve this?
You can't do it directly like that... you can do something like this though (not very pretty...):
SELECT
t.id,
t.type,
t2.id AS id2,
t3.id AS id3
FROM t
LEFT JOIN t2 ON t2.id = t.id AND t.type = 't2'
LEFT JOIN t3 ON t3.id = t.id AND t.type = 't3'
ugly way:
Table Types, T1, T2:
SELECT ... FROM Types, T1 , where Types.ID=T1.Types_ID AND Types.TYPE='TABLE1'
UNION
SELECT ... FROM Types, T2 , where Types.ID=T2.Types_ID AND Types.TYPE='TABLE2'
In addition to previous answer:
You can combine the two left joins results by using IF statement:
IF(t.type= 't2', t2.id, t3.id) as type_id
You can see another mysql conditional joins example at mysqldiary.com
I needed to implement such a thing with Laravel Query Builder. I was preparing a library and shouldn't rebuild the whole query, I wanted to utilize Eloquent as much as possible so I could only add a join to the query. This could be a little closer to what you want but also a lot uglier than you would expect:
SELECT
`comments`.*,
`commentable`.`created_at` AS `commentable_created_at`
FROM
`comments`
LEFT JOIN ((
SELECT
*,
CONCAT('post_', `id`) AS `morphed_key`
FROM
`posts`)
UNION (
SELECT
*,
CONCAT('image_', `id`) AS `morphed_key`
FROM
`images`)) AS `commentable` ON
CONCAT(`comments`.`commentable_type`, '_', `comments`.`commentable_id`)= `commentable`.`morphed_key`
The point of using this way is that you are now able to add WHERE clauses like WHERE commentable.owner_id=?