sql query - IF EXIST in WHERE clause - mysql

I have a query as like
SELECT *
FROM aTable
LEFT JOIN aTableTranslate
ON aTable.id = aTableTranslate.aTable_id
WHERE
aTableTransalte.language like 'en'
question is ....
is there any way to filter as like
...
WHERE
aTableTranslate.language like (IF EXIST_A_FIELD_FOR 'en' THEN 'en' ELSE IF EXIST_A_FIELD_FOR 'jp' THEN 'jp' OR 'cn')
?
I want to show list with 1. visitor's language > 2. english ... > or default language.
is it possible by query?

You could join to translation tables separately, and pick the first non-NULL translation with COALESCE, like this:
SELECT a.*, COALESCE(t1.translation, t2.translation, t3.translation) as translation
FROM aTable a
LEFT JOIN aTableTranslate t1 ON aTable.id = t1.aTable_id AND t1.language like 'en'
LEFT JOIN aTableTranslate t2 ON aTable.id = t2.aTable_id AND t2.language like 'jp'
LEFT JOIN aTableTranslate t3 ON aTable.id = t3.aTable_id AND t3.language like 'cn'

Try this:
SELECT a.*, COALESCE(IF(t1.language = 'en', t1.translation, NULL),
IF(t1.language = 'jp', t1.translation, NULL),
IF(t1.language = 'cn', t1.translation, NULL)
) AS translation
FROM aTable a
LEFT JOIN aTableTranslate t1 ON aTable.id = t1.aTable_id AND t1.language IN ('en', 'jp', 'cn')

Related

SQL query performance issues NOT EXISTS

I have the following SQL query that is bottlenecking at some point. It will make it halfway through around 900 records it returns before timing out. When I change my second select to only return certain columns it helped a bit but it is still bottlenecking somewhere.
I'm thinking there is something wrong with the way that I have the JOINs written but could use any advice.
SELECT * FROM
(SELECT * FROM TABLE1 B
INNER JOIN TABLE2 A ON B.ID_NBR = A.ID_NBR
INNER JOIN TABLE3 L ON A.CUST_NUM = L.CUST_NUM
WHERE B.SUPP_NBR = '17' AND STAT_NUM <> 4 AND BGHT_ID is not null
AND
NOT EXISTS (SELECT 1 FROM TABLE4 A WHERE A.ID_NBR = B.ID_NBR)) APPL
INNER JOIN TABLE5 ON M.PRSN_NUM = PRSN_NUM
WHERE M.LOC_ID = 'US' and (APPL.STAT_CD <> 'S' OR (APPL.STAT_CD =
'S' AND M.TXT_LOC !=
'UNKNOWN'));
UPDATE: I ended up using a LEFT JOIN instead of NOT EXISTS, changed the SELECT *, and used GROUP BY to correct the indexing issue:
SELECT * FROM
(SELECT B.ID_NBR, B.SUPP_NBR, B.STAT_NUM, B.BGHT_ID, A.CUST_NUM,
L.CUST_NUM, L.STAT_CD FROM TABLE1 B
INNER JOIN TABLE2 A ON B.ID_NBR = A.ID_NBR
INNER JOIN TABLE3 L ON A.CUST_NUM = L.CUST_NUM
LEFT JOIN TABLE4 C ON C.ID_NBR = B.ID_NBR
WHERE C.ID_NBR is null AND B.SUPP_NBR = '17' AND B.STAT_NUM <> 4
AND B.BGHT_ID is not null
GROUP BY B.ID_NBR, B.SUPP_NBR, B.STAT_NUM, B.BGHT_ID, A.CUST_NUM,
L.CUST_NUM, L.STAT_CD)
APPL
INNER JOIN TABLE5 ON M.PRSN_NUM = PRSN_NUM
WHERE M.LOC_ID = 'US' and
(APPL.STAT_CD <> 'S' OR M.TXT_LOC != 'UNKNOWN');
Can't this
(APPL.STAT_CD <> 'S'
OR (APPL.STAT_CD = 'S' AND M.TXT_LOC != 'UNKNOWN')
)
be simplified to
(APPL.STAT_CD <> 'S' OR M.TXT_LOC != 'UNKNOWN')
(It probably won't speed up the query much.)
Some of these indexes may help:
M: INDEX(LOC_ID, TXT_LOC, PRSN_NUM)
APPL: INDEX(STAT_CD)
B: INDEX(SUPP_NBR, ID_NBR)
A: INDEX(ID_NBR, CUST_NUM)
L: INDEX(CUST_NUM)

SQL INNER join take too long to execute

I have below sql query that take too long to execute, please there is an alternative for inner joins to resolve my issue?, because when I remove 3 or 4 joins the query is executed faster.
SELECT p.first_name, p.last_name, p.x, p.dob,'name', w.id_table1, w.type, w.stype, w.ploc, w.dat, w.created_at, av.item as table1_edge , av1.item as sdf ,av2.item as sd, av3.item as odor, av4.item as xz, av5.value as xxx , av9.item as cc, av10.item as cxz
FROM table1 w
INNER JOIN table2 a ON w.id_table1 = a.table1_id_table1
INNER JOIN table3 av ON a.id_table2 = av.id_table3 and av.sub_group = 'x1'
INNER JOIN table3 av1 ON a.id_table2 = av1.id_table3 and av1.sub_group = 'x2'
INNER JOIN table3 av2 ON a.id_table2 = av2.id_table3 and av2.sub_group = 'x3'
INNER JOIN table3 av3 ON a.id_table2 = av3.id_table3 and av3.sub_group = 'x4'
INNER JOIN table3 av4 ON a.id_table2 = av4.id_table3 and av4.sub_group = 'x5'
INNER JOIN table3 av5 ON a.id_table2 = av5.id_table3 and av5.sub_group = 'x6' and av6.item like 's%'
INNER JOIN table3 av6 ON a.id_table2 = av6.id_table3 and av6.sub_group = 'x7' and av6.item like 'x%'
INNER JOIN table3 av7 ON a.id_table2 = av7.id_table3 and av7.sub_group = 'x8' and av6.item like 'z%'
INNER JOIN table3 av8 ON a.id_table2 = av8.id_table3 and av8.sub_group = 'x9' and av6.item like 'y%'
INNER JOIN table3 av9 ON a.id_table2 = av9.id_table3 and av9.sub_group = 'x10'
INNER JOIN table3 av10 ON a.id_table2 = av10.id_table3 and av10.sub_group = 'x11'
INNER JOIN table0 p ON w.table0_id_table0 = p.id_table0
where w.created_at between '1991-12-09 00:00:00' and now() and user_id_user = 4
data:
table0
first_namelast_namedob...
table1id_table1 type stype ...
Have you tried to use subqueries instead for the inner joins that take longer to execute?
Example:
select a.id, b.id, c.id
from table a
inner join (
select id
from tableb
where b = 'x1'
) as b on b.id = a.id
inner join (
select id
from tablec
where c = 'x2'
) as c on c.id = a.id
Maybe you can make you query simpler like this:
SELECT p.first_name, p.last_name, p.x, p.dob,'name',
w.id_table1, w.type, w.secondary_type, w.primary_location,
w.onset, w.created_at, av.item,
IF(av.sub_group='x1', 1, 0) as val_x1,
IF(av.sub_group='x2', 1, 0) as val_x2,
IF(av.sub_group='x3', 1, 0) as val_x3,
..........
IF(av.sub_group='x11', 1, 0) as val_x11
FROM table1 w
INNER JOIN table2 a ON w.id_table1 = a.table1_id_table1
left join table3 av on a.id_table2 = av.id_table3
INNER JOIN table0 p ON w.table0_id_table0 = p.id_table0
where w.created_at between '1991-12-09 00:00:00'
and now() and user_id_user = 4
and ( (av.sub_group in ('x1', 'x2', 'x3', 'x4', 'x5', 'x10', 'x11'))
or (av.sub_group='x6' and av.item like 's%')
or (av.sub_group='x7' and av.item like 'x%')
or (av.sub_group='x8' and av.item like 'z%')
or (av.sub_group='x9' and av.item like 'y%')
)
We make just one JOIN with table table3 and move all conditions into where clause. With val_x1 .... val_x11 we can know which one value we have at av.item.
You seem to be storing things in an EAV format (entity-attribute-value). If you don't understand what this means, you can review the definitions on Wikipedia.
One solution is to use aggregation:
SELECT p.first_name, p.last_name, p.x, p.dob, 'name',
w.id_table1, w.type, w.secondary_type, w.primary_location,
w.onset, w.created_at,
MAX(CASE WHEN av.sub_group = 'x1' THEN av.item END) as table1_edge,
MAX(CASE WHEN av.sub_group = 'x1' THEN av.item END) as sdf,
. . .
FROM table1 w INNER JOIN
table2 a
ON w.id_table1 = a.table1_id_table1 INNER JOIN
table3 av
ON a.id_table2 = av.id_table3
WHERE av.sub_group IN ('x1', 'x2', . . . ) AND
w.created_at between '1991-12-09' and now() AND
user_id_user = 4
GROUP BY p.first_name, p.last_name, p.x, p.dob,
w.id_table1, w.type, w.secondary_type, w.primary_location, w.onset, w.created_at;
You also want appropriate indexes. I am guessing these are table1(user_id_user, created_at, id_table1) and table3(id_table3, sub_group, item).

MySQL: Query and join two tables

I have two tables that I believe I want to JOIN. I'm very new to this and am not completely sure…
The first table is called venues with the variables id, slug, name, etc. The second table is venue_terms with the variables id, option, venue, value. The matching variables are obviously venues.id and venue_terms.venue.
What I want to do is query venue_terms for matching values and then SELECT * FROM venues that match.
I've been working with the following query, but haven't been able to get it to work. I know INTERSECT isn't the solution, but I'm nut sure which JOIN I should use.
SELECT venue
FROM venue_terms
WHERE `option` = '1' AND `value` = '10'
INTERSECT
SELECT venue
FROM venue_terms
WHERE `option` = '2' AND `value` = '4';
I want to match those venue_terms.venue to the venues table. Can someone point me in the right direction?
UPDATE: To clarify, I'm trying to search multiple option/value combinations that ultimately have the same venue.id's. Basically, I want to able to find all of the venues where (option = 1 and value = 4) AND (option = 2 and value = 10) AND etc… where all of these are true.
You want to find venues that match conditions in two rows in table venue_terms. This can be accomplished by various methods. The most usual is by joining that table twice (another would be by a grouping query).
Here's the first way. Join twice to the venue_terms table:
SELECT v.id --- whatever columns you need
, v.slug --- from the venues table
, v.name
FROM venues AS v
INNER JOIN venue_terms AS vt1
ON vt1.venue = v.id
INNER JOIN venue_terms AS vt2
ON vt2.venue = v.id
WHERE ( vt1.option = 1 AND vt1.value = 10 )
AND ( vt2.option = 2 AND vt2.value = 4 ) ;
If you have 3 conditions, join thrice. If you have 10 conditions, join 10 times. It would be good for the efficiency of the query to have a compound index on (option, value, venue) in the terms table.
try this
SELECT venue.*, venue_terms.*
FROM venue
INNER JOIN venue_terms ON venue.id = venue_terms.venue
WHERE venue_terms.option IN ( 1 ,2)
AND venue_terms.value IN (10,4)
GROUP BY venue.id
How about this?
SELECT t1.*, t2.*
FROM venue t1 JOIN venue_terms t2
ON t1.id = t2.venue
WHERE (t2.option = 1 AND t2.value = 10)
NOTE: I believe option and value are of type INT.
If they are of type varchar then change above query to
SELECT t1.*, t2.*
FROM venue t1 JOIN venue_terms t2
ON t1.id = t2.venue
WHERE (t2.option = '1' AND t2.value = '10')
Update 1
As per your new requirement, you will just need to add that condition with OR option as shown below.
SELECT t1.*, t2.*
FROM venue t1 JOIN venue_terms t2
ON t1.id = t2.venue
WHERE
(t2.option = 1 AND t2.value = 10)
OR
(t2.option = 3 AND t2.value = 14)
This will join the two tables and print out the venues which matches the attributes (option, value) in venue_terms:
SELECT v.* FROM venue v, venue_terms vt
WHERE v.id = vt.venue
AND vt.option = 1
AND vt.value = 10

Mysql update using values from select

I have two queries. The first will return multiple rows:
SELECT parent_entry_id,child_entry_id FROM exp_playa_relationships WHERE parent_field_id = '34';
...And I would like to use the values (parent_entry_id,child_entry_id) and incorporate them into this query, replacing 'x' and 'y', and do it for each row returned by the first query.
UPDATE exp_channel_data AS t1,
(
SELECT field_id_46,field_id_47 FROM exp_channel_data WHERE entry_id = 'x') AS t2
SET t1.field_id_60 = t2.field_id_46, t1.field_id_61 = t2.field_id_47
WHERE t1.entry_id = 'y';
I think I need to use another JOIN, but I can't figure out how to implement one in my example. Any help would be much appreciated.
I think this is what you're after:
UPDATE exp_playa_relationships AS t0
JOIN exp_channel_data AS t1
ON t1.entry_id = t0.child_entry_id
JOIN exp_channel_data AS t2
ON t2.entry_id = t0.parent_entry_id
SET t1.field_id_60 = t2.field_id_46
, t1.field_id_61 = t2.field_id_47
Try this query
UPDATE exp_channel_data a1 INNER JOIN exp_playa_relationships a ON a1.entry_id = a.child_entry_id
INNER JOIN exp_channel_data b ON a.parent_entry_id = b.entri_id
SET a1.field_id_60 = b.field_id_46, ta1.field_id_61 = b.field_id_47
WHERE parent_field_id = '34'
Thanks all for your replies. The working syntax is:
UPDATE exp_channel_data AS t1,
(
SELECT
entry_id as ei2, child_entry_id, parent_entry_id, field_id_46 as f46,field_id_47 as f47
FROM
exp_channel_data JOIN exp_playa_relationships ON entry_id=child_entry_id AND parent_field_id = 34) AS t2
SET t1.field_id_60 = f46, t1.field_id_61 = f47
WHERE t1.entry_id=parent_entry_id;
Or in a more classic syntax, you need to adjust to your own foo & bar attributes, but use something like the following:
update exp_channel_data t1
set (t1.field_id_60,t1.field_id_61) = (
select t2.field_id_46 , t2.field_id_47
from exp_channel_data t2
where 1=1
and t2.entry_id = 'x'
and /* ENTER YOUR t1-t2 join condition here */
)
where 1=1
and t1.entry_id = y
;
But since you are MySQL I don't believe it supports compound subquery. As such:
update exp_channel_data t1
set t1.field_id_60 = (
select t2.field_id_46
from exp_channel_data t2
where 1=1
and t2.entry_id = 'x'
and /* ENTER YOUR t1-t2 join condition here */
) , t1.field_id_61 = (
select t3.field_id_47
from exp_channel_data t3
where 1=1
and t3.entry_id = 'x'
and /* ENTER YOUR t1-t3 join condition here */
)
where 1=1
and t1.entry_id = y
;

MySQL how to join on same table including missing rows

I have a table with text in various language. Its defined like this:
Id|Language|Text
EXAMPLE DATA
0, ENU, a
0, DAN, b
1, ENU, c
2, ENU, d
2, DAN, e
3, ESP, f
3, ENU, g
Language and Id form the key.
Now I want to extract all texts in a langauge (lets say english) and have the coorosponding text in another language (lets say danish) shown in the column next to. So the result should be:
0, a, b
1, c,
2, d, e
3, g
I know I can do a join like this:
SELECT t1.Id, t1.Text AS "ENU", t2.Text AS "DAN" table as t1
JOIN table as t2 ON (t1.Id= t2.Id)
WHERE t1.Langauge = "ENU" AND t2.Language = "DAN";
But this does not include the missing rows (ie row id=1 and id=3). How to do this?
* UPDATE ****
I get suggestion to use LEFT JOIN but I cant get it working. Maybe because my table layout is a bit different than in the simplified question above. My table is defined as this:
Language|MPageId|MFieldId|MParagraph|MText
Where Language,MPageId,MFieldId,MParagraph forms the key
I tried this:
SELECT t1.MPageId, t1.MFieldId, t1.MParagraphId, t1.MText, t2.MText
FROM main as t1 LEFT JOIN main as t2 ON (t1.MPageId = t2.MPageId AND
t1.MFieldId = t2.MFieldId AND t1.MParagraphId = t2.MParagraphId) WHERE
t1.MLanguage = 'ENU' AND t2.MLanguage = 'DAN'
SELECT t1.Id, t1.Text AS "ENU", t2.Text AS "DAN" FROM table as t1
LEFT JOIN table as t2 ON (t1.Id= t2.Id AND t2.Language = "DAN")
WHERE t1.Langauge = "ENU"
You do need the left join... but the "AND" clause for "DAN"ish would be applied AT the LEFT JOIN, and not in the WHERE clause... The where clause implies an INNER JOIN
SELECT
t1.Id,
t1.Text AS "ENU",
t2.Text AS "DAN"
from
YourTable t1
LEFT JOIN YourTable t2
ON t1.Id= t2.Id
AND t2.Language = "DAN"
where
t1.Langauge = "ENU"
You want a Left Join: http://www.tizag.com/mysqlTutorial/mysqlleftjoin.php
select Id,
MAX(case when LanguageS='ENU' then Text else null end ) as A,
MAX( case when LanguageS<>'ENU' then Text else null end ) as B
from LAN
GROUP BY 1
Id A B
0 a b
1 c ?
2 d e
3 g f