I am using mysql and I'm interested in rows where reciprocals appear in a different row in the table.
Imagine 2 columns, each with letters a through z.
Lets say row1 has a,b, row2 has a,c, and row 3 has c,a. I am interested in the pair a,c because it appears both as c,a and a,c in different rows in the table.
Do I have to use a nested select? Or perhaps an exists clause?
I believe this is what you're after, a self-join:
SELECT t1.*
FROM table1 t1
JOIN table1 t2
ON t1.col1 = t2.col2
AND t1.col2 = t2.col1
Here is a SQL fiddle demo: SQL Fiddle
also use SELECT REVERSE('abc') see http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_reverse with above #spencer7593 said
`SELECT t1.*
FROM table1 t1
JOIN table1 t2
ON t1.col1 = t2.col2
AND t1.col2 = t2.col1`
Related
Why would I use a LEFT JOIN in SQL in a FROM clause and attach a WHERE clause where the entity "is null"? I was told this is a very efficient script and I should learn the methodology behind it.
For example:
FROM
something
LEFT JOIN aRow a AND bRow b AND cRow c AND dRow d
WHERE
bRow.b IS NULL;
This kind of construct is used when you specifically want to know something like "a list of all customers who have never ordered anything" :
SELECT
customer.*
FROM
customers
LEFT JOIN
orders
ON
orders.customerid = customers.id
WHERE
orders.id IS NULL
Or to quote an old manager of mine: "Can you get the database to give me a list of everything that isn't in the database?"
Me> "Sure, can you give me a list of what things the database should tell you it doesn't have?"
Him> "How am I supposed to know that?"
This really is a fairly generic, non-RDBMS-specific question. The logic will apply to pretty much any flavor of SQL. And this is a technique that anyone who works with data queries should be familiar with.
For all intents and purposes (and moving past the flawed syntax in the OP), this is the same query as:
SELECT *
FROM table1
WHERE table1.col1 NOT IN (
SELECT table2.col1 FROM table2 WHERE table2.col2 = <filterHere>
)
When you are dealing with a couple of hundred rows, you may not see a significant difference in performance. But when you're working with just a few million rows in both tables, you will most definitely see a significant performance increase in
SELECT table1.*
FROM table1
LEFT OUTER JOIN table2 ON table1.col1 = table2.col1
AND table2.col2 = 42
WHERE table2.id IS NULL
Let's illustrate what is happening with these queries.
Create test tables.
CREATE TABLE table1 (col1 int, col2 varchar(10)) ;
INSERT INTO table1 ( col1, col2 )
VALUES (1,'a')
, (2,'b')
, (3,'c')
, (4,'d')
CREATE TABLE table2 (col1 int, col2 varchar(10)) ;
INSERT INTO table2 ( col1, col2 )
VALUES (1,'a')
, (3,'c')
This gives us
table1
col1 col2
1 a
2 b
3 c
4 d
table2
col1 col2
1 a
3 c
Now we want the columns that are in table1 but not in table2.
SELECT t1.col1, t1.col2
FROM table1 t1
WHERE t1.col1 NOT IN (
SELECT t2.col1 FROM table2 t2
)
We can't SELECT anything from table2, because that table is just a sub-query and not part of the whole query. It's not available to us.
This breaks down to
SELECT t1.col1, t1.col2
FROM table1 t1
WHERE t1.col1 NOT IN ( 1,3 )
Which further breaks down to
SELECT t1.col1, t1.col2
FROM table1 t1
WHERE t1.col1 <> 1
OR t1.col1 <> 3
These queries give us
col1 col2
2 b
4 d
That's a subquery broken down into 2 different OR statements to filter our results.
So lets look at a JOIN. We want all of the records on the left side, and only include those on the right side that match. So
SELECT t1.col1 AS t1_col1, t1.col2 AS t1_col2, t2.col1 AS t2_col1, t2.col2 AS t2_col2
FROM table1 t1
LEFT OUTER JOIN table2 t2 ON t1.col1 = t2.col1
With a JOIN, both tables are available to our SELECT, so we can see which records in tablel2 match up to those in table1. The above gives us
t1_col1 t1_col2 t2_col1 t2_col2
1 a 1 a
2 b NULL NULL
3 c 3 c
4 d NULL NULL
With the extra data, we can see that col1 for 2 and 4 don't match in the two tables. We can now filter those out with a simple WHERE statement.
SELECT t1.col1, t1.col2
FROM table1 t1
LEFT OUTER JOIN table2 t2 ON t1.col1 = t2.col1
WHERE t2.col1 IS NULL
Giving us
col1 col2
2 b
4 d
There's no subquery and just one statement in the filter. Plus, this allows the engine's optimizer to make a more efficient query plan.
It's impossible to see a difference in performance when we're only dealing with a couple of rows, but multiply these tables by a few million rows, and you will definitely see how much faster a JOIN can be.
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
I have a simple MYSQL query that unions two tables:
SELECT * FROM (
SELECT col1 AS col1A FROM table1
UNION
SELECT col1 AS col1B FROM table2
) AS t WHERE col1A <> col1B
I have a column called col1 in both tables and I need to select only rows that have a different value of that column so I select them as aliases. When I run this query I got:
Unknown column 'col1B' in 'where clause'
Table1 data:
col1
----
test
Table2 data:
col1
----
test
The query should return no rows as each value in col1 in table1 is equal to each value in col1 in table2 instead it returns that col1 in table2 is unknown although I select it as an alias
I think you need to look up the appropriate usage of UNION. It will return all results from first query combined with all results from the second query. This results in a single dataset, with a single column (not col1 and col2), just col1 in this case.
Assuming you're trying to get all records in table1 that don't exist in table2, you can use NOT EXISTS:
SELECT col1
FROM table1 t1
WHERE NOT EXISTS (
SELECT 1
FROM table2 t2
WHERE t1.col1 = t2.col1
)
Why Error 1054 is being returned by OP query
The error that's being returned is because the name assigned to a column from the result of a UNION is taken from the first SELECT.
You can observe this by running a simple example:
SELECT 1 AS one
UNION
SELECT 2 AS two
The resultset returned by that query will contain a single column, the name assigned to the column will be one, the column name from the first SELECT. This explains why you are getting the error from your query.
One way to return rows with no match
To return values of col1 from table1 which do not match any value in the col1 column from table2...
one option to use an anti-join pattern...
SELECT t1.col1
FROM table1 t1
LEFT
JOIN table2 t2
ON t2.col1 = t1.col1
WHERE t2.col1 IS NULL
The LEFT JOIN operation returns all rows from table1, along with any "matching" rows found in table2. The "trick" is the predicate in the WHERE clause... any "matching" rows from table2 will have a non-NULL value in col1. So, if we exclude all of the rows where we found a match, we're left with rows from table1 that didn't have a match.
If we want to get rows from table2 that don't have a "matching" row in table1, we can do the same thing, just flipping the order of the tables.
If we combine the two sets, but only want a "distinct" list of "not matched" values, we can use the UNION set operator:
SELECT t1.col1
FROM table1 t1
LEFT
JOIN table2 t2
ON t2.col1 = t1.col1
WHERE t2.col1 IS NULL
UNION
SELECT s2.col1
FROM table2 s2
LEFT
JOIN table1 s1
ON s1.col1 = s2.col1
WHERE s1.col1 IS NULL
--
Finding out which table the non-matched value is from
Sometimes, we want to know which query returned the value; we can get that by including a literal value as a discriminator in each query.
SELECT 'table1' AS src
, t1.col1
FROM table1 t1
LEFT
JOIN table2 t2
ON t2.col1 = t1.col1
WHERE t2.col1 IS NULL
UNION
SELECT 'table2' AS src
, s2.col1
FROM table2 s2
LEFT
JOIN table1 s1
ON s1.col1 = s2.col1
WHERE s1.col1 IS NULL
ORDER BY 2
A different (usually less performant) approach to finding non-matching rows
An entirely different approach, to returning an equivalent result, would be do something like this:
SELECT q.col1
FROM ( SELECT 't1' AS src, t1.col1 FROM table1 t1
UNION
SELECT 't2' AS src, t2.col1 FROM table2 t2
) q
GROUP BY q.col1
HAVING COUNT(DISTINCT q.src) < 2
ORDER BY q.col1
(The inline view q will be "materialized" as a derived table, so this approach can be expensive for large sets, and this approach won't take advantage of indexes on col1 to perform the matching.) One other small difference between this and the anti-join approach: this will omit a col1 value of NULL if a NULL exists in both tables. Aside from that, the resultset is equivalent.
I have a query say,
select col1,col2 from table1;
which return 2 columns of multiple rows. I want to use these two values in where condition of another query. Something like
select col3,col4 from table2 where col5=col1 and col6=col2;
where col1 and col2 are the resultant values of the first query.
Currently I have used inner query something like
select col3,col4 from table2
where col5 in (select col1 from table1)
and col6 in (select col2 from table1);
But I dont want to use inner query like the one shown above as it slows down bring results.
Please suggest.
JOIN them instead of using IN's like so:
SELECT t2.col3, t2.col4
FROM table2 t2
INNER JOIN
(
SELECT col1, col2
FROM table1
) t1 ON t2.col5 = t1.col1 AND t2.col6 = t1.col2
Note that, you didn't need to select specific columns in the second table. You can JOIN the second table table1 directly like so:
SELECT t2.col3, t2.col4
FROM table2 t2
INNER JOIN table1 t1 ON t2.col5 = t1.col1
AND t2.col6 = t1.col2
I have two tables. t1 and t2. I want to select the values that are from t1 and occurred in t2. What I wrote is the following:
select col1 from t1, t2
where t1.col1y=t2.col2;
Is this is the right way to search for the value ?
Yes, that works, but it's the old form of writing a join. Use the new form:
select t1.col1
from t1
inner join t2 on t1.col1 = t2.col2