So I apologize if this has come up before, but I couldn't find a solid answer.
I am trying to get a single column of ids from a set of 3 columns in my table joined with another table.
The select statement just to get a single column would be like this:
SELECT id FROM TableA JOIN TableB USING (key1, key2) WHERE someValue = X;
Now as I understand it I can do unions to get these like so:
SELECT spec_id1 AS id FROM TableA JOIN TableB USING (key1, key2) WHERE someValue1 = X
UNION
SELECT spec_id2 AS id FROM TableA JOIN TableB USING (key1, key2) WHERE someValue2 = Y
UNION
SELECT spec_id3 AS id FROM TableA JOIN TableB USING (key1, key2) WHERE someValue3 = Z
Is there a way to reuse the TableA JOIN TableB USING (key1, key2) so it isn't joined for each select? I also have a WHERE condition that applies to all of the selects that is not shown above. Could I possibly reuse something like:
FROM TableA JOIN TableB USING (key1, key2) WHERE someOtherValue = W
I am trying to do this in PHP using mysqli. My original instinct was to use a temp table and query that, but I'm not sure how to handle that in mysqli. If I can use the table for multiple following queries that would be doubly ideal as there is extra data in the joined tables that could be used later.
Sorry if this is naive, but I'm not really a big web developer. Thanks in advance.
EDIT:
I am looking into temporary tables, and it seems like that might be a good way around it. I'd still like some confirmation on whether that's a good idea or not before doing anything with it.
There is no shortcut - not without changing the tables' design. Your approach is solid and you should not worry about having 3 joins in your query.
If the 3 lists of spec_ids are known to not have any overlapping values, then you could improve performance by changing UNION to UNION ALL.
One possible rewriting, without changing the overall UNION plan, is to change joins to EXISTS subqueries:
SELECT spec_id1 AS id
FROM TableA
WHERE EXISTS
( SELECT *
FROM TableB
WHERE (TableB.key1, TableB.key2) = (TableA.key1, TableA.key2)
AND someValue1 = X
)
UNION --- or UNION ALL
...
UNION
...
or - if the spec_ids are all included in another BaseTable - you can have something like this which might yield a better execution plan:
SELECT id
FROM BaseTable
WHERE EXISTS
( SELECT * AS id
FROM TableA
JOIN TableB
USING (key1, key2)
WHERE someValue1
AND TableA.spec_id1 = BaseTable.id
)
OR EXISTS
(
...
)
OR ...
Try CASE statement. You should be able to do it without the UNION
SELECT
CASE
WHEN someValue1 = X THEN spec_id1
WHEN someValue2 = Y THEN spec_id2
WHEN someValue3 = Z THEN spec_id3
END
AS id FROM TableA JOIN TableB USING (key1, key2)
WHERE
someValue1 = X OR someValue2 = Y OR WHERE someValue3 = Z
Related
table1 (id, name)
table2 (id, name)
Query:
SELECT name
FROM table2
-- that are not in table1 already
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL
Q: What is happening here?
A: Conceptually, we select all rows from table1 and for each row we attempt to find a row in table2 with the same value for the name column. If there is no such row, we just leave the table2 portion of our result empty for that row. Then we constrain our selection by picking only those rows in the result where the matching row does not exist. Finally, We ignore all fields from our result except for the name column (the one we are sure that exists, from table1).
While it may not be the most performant method possible in all cases, it should work in basically every database engine ever that attempts to implement ANSI 92 SQL
You can either do
SELECT name
FROM table2
WHERE name NOT IN
(SELECT name
FROM table1)
or
SELECT name
FROM table2
WHERE NOT EXISTS
(SELECT *
FROM table1
WHERE table1.name = table2.name)
See this question for 3 techniques to accomplish this
I don't have enough rep points to vote up froadie's answer. But I have to disagree with the comments on Kris's answer. The following answer:
SELECT name
FROM table2
WHERE name NOT IN
(SELECT name
FROM table1)
Is FAR more efficient in practice. I don't know why, but I'm running it against 800k+ records and the difference is tremendous with the advantage given to the 2nd answer posted above. Just my $0.02.
SELECT <column_list>
FROM TABLEA a
LEFTJOIN TABLEB b
ON a.Key = b.Key
WHERE b.Key IS NULL;
https://www.cloudways.com/blog/how-to-join-two-tables-mysql/
This is pure set theory which you can achieve with the minus operation.
select id, name from table1
minus
select id, name from table2
Here's what worked best for me.
SELECT *
FROM #T1
EXCEPT
SELECT a.*
FROM #T1 a
JOIN #T2 b ON a.ID = b.ID
This was more than twice as fast as any other method I tried.
Watch out for pitfalls. If the field Name in Table1 contain Nulls you are in for surprises.
Better is:
SELECT name
FROM table2
WHERE name NOT IN
(SELECT ISNULL(name ,'')
FROM table1)
You can use EXCEPT in mssql or MINUS in oracle, they are identical according to :
http://blog.sqlauthority.com/2008/08/07/sql-server-except-clause-in-sql-server-is-similar-to-minus-clause-in-oracle/
That work sharp for me
SELECT *
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL
You can use following query structure :
SELECT t1.name FROM table1 t1 JOIN table2 t2 ON t2.fk_id != t1.id;
table1 :
id
name
1
Amit
2
Sagar
table2 :
id
fk_id
email
1
1
amit#ma.com
Output:
name
Sagar
All the above queries are incredibly slow on big tables. A change of strategy is needed. Here there is the code I used for a DB of mine, you can transliterate changing the fields and table names.
This is the strategy: you create two implicit temporary tables and make a union of them.
The first temporary table comes from a selection of all the rows of the first original table the fields of which you wanna control that are NOT present in the second original table.
The second implicit temporary table contains all the rows of the two original tables that have a match on identical values of the column/field you wanna control.
The result of the union is a table that has more than one row with the same control field value in case there is a match for that value on the two original tables (one coming from the first select, the second coming from the second select) and just one row with the control column value in case of the value of the first original table not matching any value of the second original table.
You group and count. When the count is 1 there is not match and, finally, you select just the rows with the count equal to 1.
Seems not elegant, but it is orders of magnitude faster than all the above solutions.
IMPORTANT NOTE: enable the INDEX on the columns to be checked.
SELECT name, source, id
FROM
(
SELECT name, "active_ingredients" as source, active_ingredients.id as id
FROM active_ingredients
UNION ALL
SELECT active_ingredients.name as name, "UNII_database" as source, temp_active_ingredients_aliases.id as id
FROM active_ingredients
INNER JOIN temp_active_ingredients_aliases ON temp_active_ingredients_aliases.alias_name = active_ingredients.name
) tbl
GROUP BY name
HAVING count(*) = 1
ORDER BY name
See query:
SELECT * FROM Table1 WHERE
id NOT IN (SELECT
e.id
FROM
Table1 e
INNER JOIN
Table2 s ON e.id = s.id);
Conceptually would be: Fetching the matching records in subquery and then in main query fetching the records which are not in subquery.
First define alias of table like t1 and t2.
After that get record of second table.
After that match that record using where condition:
SELECT name FROM table2 as t2
WHERE NOT EXISTS (SELECT * FROM table1 as t1 WHERE t1.name = t2.name)
I'm going to repost (since I'm not cool enough yet to comment) in the correct answer....in case anyone else thought it needed better explaining.
SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL
And I've seen syntax in FROM needing commas between table names in mySQL but in sqlLite it seemed to prefer the space.
The bottom line is when you use bad variable names it leaves questions. My variables should make more sense. And someone should explain why we need a comma or no comma.
I tried all solutions above but they did not work in my case. The following query worked for me.
SELECT NAME
FROM table_1
WHERE NAME NOT IN
(SELECT a.NAME
FROM table_1 AS a
LEFT JOIN table_2 AS b
ON a.NAME = b.NAME
WHERE any further condition);
I'm stuck in a piece of code that does not quite understand.
I have several tables with different names but same fields, but the tables are independent
Something like that:
table1
id
user
title
table2
id
user
title
I need to get in the same query data from two tables but I fail, I try with INNER JOIN, UNION ALL, but not knowing, it misapplied.
Right now I have this:
$mysites = $db->QueryFetchArrayAll("
select *
FROM table1,table2
where table1.user = table2.user AND
table1.user = 1");
foreach($mysites as $mysite){
echo $QUERY['title'];
}
but returned this:
title1.table1
title2.table1
and i like this:
title1.table1
title2.table1
title1.table2
title2.table2
A greeting and thanks
You can use the keyword UNION like this:
SELECT * FROM table1 UNION SELECT * FROM table2
This query will select everything from table1 and merge the results with those from table2. Please note that you have to select the same number of columns from both tables. Moreover, column names and datatypes will be assigned according to first table.
If you want to preserve duplicates add the keyword ALL:
SELECT * FROM table1 UNION ALL SELECT * FROM table2
The question is very unclear.....
Are the ID's the same in each table for each user? If so an INNERJOIN will help
SELECT t1.*, t2.*
FROM table1.t1
INNER JOIN table2.t2
ON t1.id = t2.id
WHERE t1.user = "1"
(Change INNER JOIN to LEFT JOIN if the data could be missing)
If this is not the case, why not put the data from one table into the other, and have just one table with all the data in it?
I have two table in the same database: hlstats_Events_Connects and hlstats_PlayerUniqueIds.
In the hlstats_Events_Connects I have a value I wish to get, however the ID it's related to I need to get from the data in another table, using the "uniqueId" that I have. Example:
**hlstats_Events_Connects**
playerId eventTime
----------------------
8 2013-04-05 05:44:14
**hlstats_PlayerUniqueIds**
playerId uniqueId
---------------------
8 0:0:84901
So I have the "uniqueId" as a variable, and I want to say, get the playerId of the persons uniqueId, then get the eventTime from what the playerId is. Currently I have something along the lines of the below, but can't figure out the Where clause.
SELECT c.eventTime, c.playerId, u.uniqueId, u.playerId
FROM c.hlstats_Events_Connects, u.hlstats_PlayerUniqueIds
WHERE ...?
Cheers
Looks like you are just missing the JOIN. You will join the tables on the playerId column:
SELECT c.eventTime, c.playerId, u.uniqueId, u.playerId
FROM c.hlstats_Events_Connects c
INNER JOIN u.hlstats_PlayerUniqueIds u
ON c.playerId = u.playerId
Note, I updated the query to use ANSI JOIN syntax, in this case an INNER JOIN. This is standard SQL syntax, instead of commas between the tables and the join in the WHERE
Use JOIN like this
SELECT c.eventTime, c.playerId, u.uniqueId, u.playerId
FROM c.hlstats_Events_Connects, u.hlstats_PlayerUniqueIds
WHERE c.playerId = u.playerId
You don't need to add prefixes to table names, instead those should be specified after table name, and also you can just join on playerId column (if those are large tables, I'd suggest adding an index to those columns.)
SELECT
c.eventTime, c.playerId, u.uniqueId, u.playerId
FROM
hlstats_Events_Connects c,
hlstats_PlayerUniqueIds u
WHERE
u.uniqueId = "0:0:84901" and
u.playerId = c.playerId
I have 2 tables table1 and table2, where table1 contains the data collected so far, and table2 contains table1's data along with some updated/additional data. I need to retrieve only this updated/additional data and insert it into table1.
Now I know I can use NOT IN to do this, but I am not sure it will be a very efficient solution in case of a huge number of records. Any suggestion on what the best approach would be in terms of execution speed?
This can be done with simple join both tables
something like below:
select t1.* from table1 as t1 join table2 as t2 on t1.id=t2.id where ...[]
I'm not sure if i've understand your question correctly but let me give it a try. Suppose you have a design like this:
TableA : {colA, colB, colC, colD, colE}
TableB : {colA, colB, RecC, RecD, RecE}
where Tables (tableA, tableB) is joined on ColA. I Assumed that TableA's columns (colC, ColD, colE) will be updated and the records are based on TableB's columns (recC, recD, recE).
In your statement: I need to retrieve only this updated/additional data and insert it into table1.. I think you want to update TableA's records based on TableB
UPDATE TableA a INNER JOIN TableB b ON a.ColA = b.ColA
SET a.ColC = b.RecC,
a.ColD = b.RecD,
a.ColE = b.RecE
-- WHERE (Condition) -- if you want to have a condition.
so the statement above updates all the records in tableA if colA also exist in tableB since I've used INNER JOIN. You could also use LEFT JOIN.
Can some one optimize this mysql query
SELECT submittedform.*, inspectors.first_name, inspectors.last_name
FROM (
SELECT `dinsp`,`departure`,`arrival`,'cabin' as type FROM cabinets
UNION
SELECT `dinsp`,`departure`,`arrival`,'cockpit' as type FROM cockpits
ORDER BY `date_of_inspection` ASC
) AS submittedform
INNER JOIN inspectors ON inspectors.id = submittedform.dinsp
I don't want to rely on nested query or is it fine in this case? Also suggest me a cakephp solution but the tables can't be related.
You can try:
SELECT sf.`dinsp`, sf.`departure`, sf.`arrival`, sf.`type`, i.`first_name`, i.`last_name`
FROM
`inspectors` AS i INNER JOIN (
SELECT `dinsp`, `departure`, `arrival`, `date_of_inspection`, 'cabin' AS `type`
FROM `cabinets`
UNION ALL
SELECT `dinsp`, `departure`, `arrival`, `date_of_inspection`, 'cockpit' AS `type`
FROM `cockpits`
) AS sf ON sf.`dinsp` = i.`id`
ORDER BY sf.`date_of_inspection`
UNION ALL will not check for duplicates. Always put the ORDER BY clause in the outer query to ensure proper ordering.
It would be better to avoid using UNION because it will not allow the query optimizer to use any index you may have on dinsp and date_of_inspection. But that would mean changing the schema.
An alternative to a UNION sub-query is to make the main query into two parts with a UNION between:
SELECT c.dinsp, c.departure, d.arrival, 'cabin' AS type, i.first_name, i.last_name
FROM cabinets AS c JOIN inspectors AS i ON i.id = c.dinsp
SELECT c.dinsp, c.departure, d.arrival, 'cockpit' AS type, i.first_name, i.last_name
FROM cockpits AS c JOIN inspectors AS i ON i.id = c.dinsp
It is not clear that this would give significantly different performance. If anything, it would be worse since it involves two scans of the Inspectors table, but that isn't likely to be very big so it may not matter very much. Your UNION sub-query minus the ORDER BY is likely to be as good as or slightly better than this. Your ORDER BY on a non-selected field is problematic in the inner query; and needs careful handling in the UNION I'm proposing (probably by selecting the extra column).
SELECT c.dinsp, c.date_of_inspection, c.departure, d.arrival, 'cabin' AS type,
i.first_name, i.last_name
FROM cabinets AS c JOIN inspectors AS i ON i.id = c.dinsp
SELECT c.dinsp, c.date_of_inspection, c.departure, d.arrival, 'cockpit' AS type,
i.first_name, i.last_name
FROM cockpits AS c JOIN inspectors AS i ON i.id = c.dinsp
ORDER BY date_of_inspection;