I have the following query:
SELECT col1, col2, col3 FROM tb1
WHERE col4=ANY(
SELECT col1 FROM tb2
WHERE col2=(SELECT col1 FROM tb3 WHERE col3='php generated string')
AND col3=(SELECT col2 FROM tb3 WHERE col3='same string as above')
);
It works, but it's very slow. I know there is a much better (and faster) way to do this, but my lack of experience with SQL queries means I'm trying to make this harder than it needs to be. I've tried using a JOIN, but I don't truly understand how to make that work in this case either.
Any help is much appreciated.
You're right that you need to learn how to use JOIN. If you ever are matching up values from one column across multiple tables, you should probably be JOINing the tables together ON that column.
SELECT tb1.col1,tb1.col2,tb1.col3
FROM tb1
JOIN tb2
ON (tb1.col4 = tb2.col1)
JOIN tb3
ON (tb1.col2 = tb3.col1
AND tb1.col3 = tb3.col2)
WHERE tb3.col3 = 'php generated string'
SELECT tb1.col1, tb1.col2, tb1.col3
FROM tb1
INNER JOIN tb2
ON tb1.col4 = tb2.col1
INNER JOIN tb3
ON tb1.col2 = tb3.col1
AND tb3.col3 = 'php generated string'
INNER JOIN tb3
ON tb1.col3 = tb3.col2
AND tb3.col3 = 'same string as above'
If the subquery within ANY can return more than one record, then rewriting your query as a JOIN will result in duplicates.
Use this:
SELECT col1, col2, col3
FROM tb1
WHERE EXISTS
(
SELECT NULL
FROM tb3
JOIN tb2
ON tb2.col2 = tb3.col1
AND tb2.col2 = tb3.col2
AND tb2.col1 = tb1.col4
WHERE tb3.col3 = 'php generated string'
)
and create the following indexes:
tb2 (col1, col2, col3)
tb3 (col3)
Related
I have a query that selects all the data from one table and specific columns from another where two columns are equal and another column equals a specific value.
SELECT table1.*, table2.column1, table2.column2 FROM table1
INNER JOIN table2 ON table1.column3=table2.column3
WHERE table1.column1='foo';
Is it possible to pull table3.column1 & table3.column2 from a table3 where table3.column3=table1.column3 AND table3.column4='bar' ?
The thing that makes it more complex is that the data in table3 is optional and may not always exist; however I still want the query to return table1 & table2's data but with table3.column1 & table3.column2 just being presented as NULL or EMPTY...
Im struggling to get my head around it myself, and any insight or assistance would be greatly appreciated.
Use left join:
SELECT table1.*, table2.column1, table2.column2, table3.column1, table3.column2
FROM table1
INNER JOIN table2
ON table1.column3 = table2.column3
LEFT JOIN table3
ON table3.column3 = table1.column3 AND table3.column4 = 'bar'
WHERE table1.column1 = 'foo';
When there is no corresponding record in table3 table3.column1 and table3.column2 will be null
And if column1 and column2 names are not unique column names in select clause you need to give them an alias
select t1.col1, t2.col2, t3.col3
from table1 as t1
inner join table2 as t2 on t2.col3.t1.col2
left join table3 as t3 on t3.col3.t2.col2
where t1.col1 = 'test';
it can be done like this.
I have a query like this:
UPDATE t1
SET t1.col1 = ( SELECT col1 FROM t2 WHERE <some_complex_conditions> ),
t1.col2 = ( SELECT col2 FROM t2 WHERE <some_complex_conditions> )
WHERE id = :id;
As you see, I have to execute the same query twice, every time for one column. Also as I've mentioned, that SELECT query has some complex conditions which need lots of processing. Now I want to know, how can I handle the UPDATE statement to get the update those two columns by single SELECT statement?
Something like this:
SELECT col1, col2 FROM t2 WHERE <some_complex_conditions>
In other word, how can I use this ^ into the UPDATE statement?
see multi table syntax in manual and stackoverflow
It's possible to update joined table. I think that it should be possible to join select statement, but I'm not sure, but I think example below shows equivalent query:
UPDATE t1
LEFT JOIN t2
-- joining condition, there can be the part <some complex condition>
ON t1.id = t2.ref_id AND t2.col3 = 'whatever you want'
SET t1.col1 = t2.col1, t1.col2 = t2.col2
--additional condition like WHERE t2.col1 IS NOT NULL
consider my scenario like i have 3 tables
table1,
table2,
table3 i want to fetch some colums from table2 or table3 on the basis of some condition
like
select tb1.*,
if(tb1.status='true' then tb2.name else tb3.name)
from table1 tb1, table2 tb2, table3 tb3
where tb1.aid=tb2.aid and tb1.aid=tb2.aid
in short i want to display some column from either table2 or table3 on the basis of condition
You can use CASE EXPRESSION :
SELECT tb1.*,
CASE WHEN tb1.status = 'true' THEN tb2.name ELSE tb3.name END as `name`
FROM table1 tb1
INNER JOIN table2 tb2
ON(t1.aid = tb2.aid)
INNER JOIN table3 tb3
ON(tb1.aid = tb3.aid)
Or with IF() like you wanted :
SELECT tb1.*,
IF(tb1.status='true' ,tb2.col1,tb3.col1) as col1,
IF(tb1.status='true' ,tb2.col2,tb3.col2) as col2,
IF(tb1.status='true' ,tb2.col3,tb3.col3) as col3
.....
Also, try to avoid the use of implicit join syntax(comma separated) and use the proper syntax of a join, this will help you avoid mistakes like the one you did (compared both conditions to tb2 instead of one to tb2 and one to tb3
if(tb1.status='true',tb2.name,tb3.name) as name
SELECT
tb1.*
, CASE
WHEN tb1.status = 'true' THEN tb2.name
ELSE tb3.name
END AS var_name
FROM table1 tb1
INNER JOIN table2 tb2 ON tb1.aid = tb2.aid
INNER JOIN table3 tb3 ON tb2.aid = tb3.aid
Use a case expression
BUT, you also need to look hard at how you are joining the tables. There are 2 things to note:
stop using comma separated lists of tables, there is a more precise syntax available for joins
you currently (in the question) don't have a proper join to table3
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')
Clearly, I am not a SQL guy, so I have to ask for help on the following rather simple task.
I have two SQL Server 2008 tables: t1 and t2 with many identical columns and a key column (entry_ID). T2 has rows that do not exist in t1 but should.
I want to merge those rows from t2 that do not exist in t1 but I also do not want any rows from t2 that already exist in t1. I would like the result set to fill a new t3.
I have looked at many solutions online but can't find the solution to the above scenario.
Thank you.
There are a number of ways to do it you could use UNION ALL or OUTER JOIN.
Assuming you are using Entry_ID to find identical records, and Entry_ID is unique within each table, here is a OUTER JOIN method:
This gets you your recordset: T1 and T2 merged:
SELECT
CASE
WHEN T1.Entry_ID IS NULL THEN 'T2'
WHEN T2.Entry_ID IS NULL THEN 'T1'
ELSE 'Both'
END SourceTable,
COALESCE(T1.Entry_ID,T2.Entry_ID) As Entry_ID,
COALESCE(T1.Col1, T2.Col1) As Col1,
COALESCE(T1.Col2, T2.Col2) As Col2,
COALESCE(T1.Col3, T2.Col3) As Col3,
COALESCE(T1.Col4, T2.Col4) As Col4
FROM T1 FULL OUTER JOIN T2
ON T1.Entry_DI = T2.Entry_ID
ORDER BY COALESCE(T1.Entry_DI,T2.Entry_ID)
This inserts it into T3:
INSERT INTO T3 (Entry_ID,Col1, COl2,Col3,Col4)
SELECT
COALESCE(T1.Entry_DI,T2.Entry_ID) As Entry_ID,
COALESCE(T1.Col1, T2.Col1) As Col1,
COALESCE(T1.Col2, T2.Col2) As Col2,
COALESCE(T1.Col3, T2.Col3) As Col3,
COALESCE(T1.Col4, T2.Col4) As Col4
FROM T1 FULL OUTER JOIN T2
ON T1.Entry_DI = T2.Entry_ID
Again you must note that Entry_ID needs to be unique within their tables, and it uses this to match between the tables.
Also note the columns from the select line up with the column list in the insert statement - the order of the columns in the physical table doesn't matter, the INSERT and SELECT just have to line up.