Merging multiple queries preferentially - mysql

I'd like to be able to merge two sorted queries, and merge them, preferring things in the first query (i.e. except for duplicates, everything in the first query is favored over everything in the second query). Better still, I'd be able to do this with one query, rather than multiple queries (although I'm not too picky).
For example, if the first query returned:
"Apple"
"Bat"
"Dolphin"
And the second one returned:
"Cat"
"Dolphin"
"Elephant"
I'd want the results to look like this:
"Apple"
"Bat"
"Dolphin"
"Cat"
"Elephant"
If it helps, I'm trying to implement a search feature, but want it to be flexible. The first query may be things that exactly match, the second may be things that begin with the query string, and a third, for example, may be things that contain the query string anywhere.
Each query is a superset of the previous query.

You could achieve by using UNION to select values from all tables and giving each table an order value.
select distinct Word
from
(
select Word, 1 as WordOrder from table1
union
select Word, 2 as WordOrder from table2
) X
order by WordOrder
SQL Fiddle demo

I would suggest to do a union select. You can use different conditions in where for each query and merge the result:
SELECT * FROM table1
WHERE ...
UNION
SELECT * FROM table1
WHERE ...
You can even merge the result from different tables, if the columns in result are the same in all querys:
SELECT * FROM table1
WHERE ...
UNION
SELECT * FROM table2
WHERE ...

Related

How to combine multiple Select queries in a single one MySql

In a webpage I want to display several tables with information.
To do that, at the moment I do
SELECT * FROM tableONE WHERE field LIKE 'criteria'
then I process the result in a foreach loop. Then I do another query to the next table and process it again
SELECT * FROM tableTWO WHERE field LIKE 'criteria'
....
SELECT * FROM tableTWENTY WHERE field LIKE 'criteria'
I've the feeling that making 20 connections with the database is suboptimal and I could make a single query and in the foreach loop put each result in the appropriate table. The issues I found to do it are:
There is no related column amongst them, so I can not do a JOIN ON.
If I do a cartesian join I get many redundant rows
I can not use UNION because the columns on each table are different.
What is the most efficient way to do this?
Thanks
I've tried JOIN, UNION and separating the tables with comas (cartesian join), but they don't give the expected result
Just use UNION Clause
SELECT field1, field2, filed3 FROM table1
UNION
SELECT field1, NULL as filed2, field4 as filed3 FROM table2
;
Beware that
Every SELECT statement within UNION must have the same number of columns
The columns must also have similar data types

SELECT multiple columns from multiple tables and don't fill blank spaces

I have what I believe to be a pretty unique use case. I would like to be able to runs a single SELECT statement on a database where I get one column from four tables. I need to run where clauses on each different table where I have one main clause that will be across each of the tables and I am not able to JOIN because the data in each column will be a different length and I don't want to have duplicate items.
I have an example of the Select statement below. Also I understand if this is not possible.
SELECT s.service_id, u.id AS "user_id", h.mac_address, l.id AS "location_id" FROM services s
LEFT JOIN db.av_product ap ON s.product_id = ap.id
WHERE s.customer_code LIKE 'test_customer'
AND u.customer_code LIKE 'test_customer'
AND h.customer_code LIKE 'test_customer'
AND l.customer_code LIKE 'test_customer'
AND s.parent_id IS NULL
AND s.active=0
AND ap.sku NOT REGEXP 'fakeregex'
AND l.active = "1"
AND h.hardware_id NOT IN ('44','45')
AND (u.support_user != 1 OR u.support_user IS NULL);
TIA!
You will need to use joins for your tables to make a single query OR you can try multiple queries merged with UNION keyword.
If you want to make a single query, have a look about SELECT DISTINCT or GROUP BY for handling duplicates.
wut up?
do you know what UNION is?
The UNION operator is used to combine the result-set of two or more SELECT statements.
but every SELECT statement within UNION must have the same number of columns; so there we got a problem.
you can handle it with WHERE operator so I won't get in to it.
anyway, UNION!
shall we?
SELECT column_name(s) FROM table1
UNION
SELECT column_name(s) FROM table2;
anyway; your solution is UNION, maybe not like what I wrote.
you can try this link too.
https://www.w3schools.com/mysql/mysql_union.asp
have a clean code

SQL UNION ALL to eliminate duplicates

I found this sample interview question and answer posted on toptal reproduced here. But I don't really understand the code. How can a UNION ALL turn into a UNIION (distinct) like that? Also, why is this code faster?
QUESTION
Write a SQL query using UNION ALL (not UNION) that uses the WHERE clause to eliminate duplicates. Why might you want to do this?
Hide answer
You can avoid duplicates using UNION ALL and still run much faster than UNION DISTINCT (which is actually same as UNION) by running a query like this:
ANSWER
SELECT * FROM mytable WHERE a=X UNION ALL SELECT * FROM mytable WHERE b=Y AND a!=X
The key is the AND a!=X part. This gives you the benefits of the UNION (a.k.a., UNION DISTINCT) command, while avoiding much of its performance hit.
But in the example, the first query has a condition on column a, whereas the second query has a condition on column b. This probably came from a query that's hard to optimize:
SELECT * FROM mytable WHERE a=X OR b=Y
This query is hard to optimize with simple B-tree indexing. Does the engine search an index on column a? Or on column b? Either way, searching the other term requires a table-scan.
Hence the trick of using UNION to separate into two queries for one term each. Each subquery can use the best index for each search term. Then combine the results using UNION.
But the two subsets may overlap, because some rows where b=Y may also have a=X in which case such rows occur in both subsets. Therefore you have to do duplicate elimination, or else see some rows twice in the final result.
SELECT * FROM mytable WHERE a=X
UNION DISTINCT
SELECT * FROM mytable WHERE b=Y
UNION DISTINCT is expensive because typical implementations sort the rows to find duplicates. Just like if you use SELECT DISTINCT ....
We also have a perception that it's even more "wasted" work if the two subset of rows you are unioning have a lot of rows occurring in both subsets. It's a lot of rows to eliminate.
But there's no need to eliminate duplicates if you can guarantee that the two sets of rows are already distinct. That is, if you guarantee there is no overlap. If you can rely on that, then it would always be a no-op to eliminate duplicates, and therefore the query can skip that step, and therefore skip the costly sorting.
If you change the queries so that they are guaranteed to select non-overlapping subsets of rows, that's a win.
SELECT * FROM mytable WHERE a=X
UNION ALL
SELECT * FROM mytable WHERE b=Y AND a!=X
These two sets are guaranteed to have no overlap. If the first set has rows where a=X and the second set has rows where a!=X then there can be no row that is in both sets.
The second query therefore only catches some of the rows where b=Y, but any row where a=X AND b=Y is already included in the first set.
So the query achieves an optimized search for two OR terms, without producing duplicates, and requiring no UNION DISTINCT operation.
The most simple way is like this, especially if you have many columns:
SELECT *
INTO table2
FROM table1
UNION
SELECT *
FROM table1
ORDER BY column1
I guest this is right (Oracle):
select distinct * from (
select * from test_a
union all
select * from test_b
);
The question will be correct if the table has unique identifier - primary key. Otherwise every select can return many the same rows.
To understand why it can faster let's look at how database executes UNION ALL and UNION.
The first is simple joining results from two independent queries. These queries can be processed in parallel and taken to client one by one.
The second is joining + distinction. To distinct records from 2 queries db needs to have all them in memory or if memory is not enough db needs to store them to temporary table and next select unique ones. This is where performance degradation can be. DB's are pretty smart and distinction algorithms are developed good but for large result sets it could be a problem anyway.
UNION ALL + additional WHERE condition can be faster if an index will be used while filtering.
So, here the performance magic.
I guess it will work
select col1 From (
select row_number() over (partition by col1 order by col1) as b, col1
from (
select col1 From u1
union all
select col1 From u2 ) a
) x
where x.b =1
This will also do the same trick:
select * from (
select * from table1
union all
select * from table2
) a group by
columns
having count(*) >= 1
or
select * from table1
union all
select * from table2 b
where not exists (select 1 from table1 a where a.col1 = b.col1)

MYSQL nested select query from same table

What I am trying to do is select each distinct column1 value from table1 and then select all the columns from those rows returned from the above. Is this possible at all?
What I have so far, however, nothing is returned:
SELECT * FROM (SELECT DISTINCT column1 FROM table1)
I've thought about putting a unique/distinct restriction in the where clause of the query:
SELECT * FROM table1 WHERE some_unique_determiner column1
Any ideas how I could go about achieving the desired output?
Ok so answering my own question. What I need to do was to group the data by column1, without use of a nested query. Many thanks to #VR46 for the help.
SELECT * FROM table1 GROUP BY column1
Returned all columns from each unique value from column1
In your next posts, it will be better if you post your table structures, input and desired out put so it will be easier for us to understand.
If I did understand, there is one of two options:
Either you have duplicates, and you want to eliminate them so your correct query should be
select distinct COLUMNa,COLUMNb,COLUMNc... ETC
which will drop duplicates(that the entire row is the same).
Or you want to eliminate rows that have the same column1 and it doesn't matter if all the rest is the same or not.
In that case, You need to tell us which one of the result you want to keep, The up to date one,the older, random ETC.. because right now its impossible to make you a query that selects all the columns after you distinct, since all the duplicates will return like this:
SELECT * FROM TABLE WHERE COLUMN1 IN(SELECT DISTINCT COLUMN1 FROM TABLE)
Which is a wrong query since it doesn't do anything.

mysql query two tables, UNION and where clause

I have two tables.
I query like this:
SELECT * FROM (
Select requester_name,receiver_name from poem_authors_follow_requests as one
UNION
Select requester_name,receiver_name from poem_authors_friend_requests as two
) as u
where (LOWER(requester_name)=LOWER('user1') or LOWER(receiver_name)=LOWER('user1'))
I am using UNION because i want to get distinct values for each user if a user exists in the first table and in the second.
For example:
table1
nameofuser
peter
table2
nameofuser
peter
if peter is on either table i should get the name one time because it exists on both tables.
Still i get one row from first table and a second from table number two. What is wrong?
Any help appreciated.
There are two problems with your SQL:
(THis is not the question, but should be considered) by using WHERE over the UNION instead of the tables, you create a performance nightmare: MySQL will create a temporary table containing the UNION, then query it over the WHERE. Using a calculation on a field (LOWER(requester_name)) makes this even worse.
The reason you get two rows is, that UNION DISTINCT will only suppress real duplicates, so the tuple (someuser,peter) and the tuple (someotheruser, peter) will result in duplication.
Edit
To make (someuser, peter) a duplicate of (peter, someuser) you could use:
SELECT
IF(requester_name='peter', receiver_name, requester_name) AS otheruser
FROM
...
UNION
SELECT
IF(requester_name='peter', receiver_name, requester_name) AS otheruser
FROM
...
So you only select someuser which you already know : peter
You need the where clause on both selects:
select requester_name, receiver_name
from poem_authors_follow_requests
where LOWER(requester_name) = LOWER('user1') or LOWER(receiver_name) = LOWER('user1')
union
select requester_name, receiver_name
from poem_authors_friend_requests
where LOWER(requester_name) = LOWER('user1') or LOWER(receiver_name) = LOWER('user1')
The two queries are independent of each other, so you shouldn't try to connect them other than by union.
You can use UNION if you want to select rows one after the other from several tables or several sets of rows from a single table all as a single result set.
UNION is available as of MySQL 4.0. This section illustrates how to use it.
Suppose you have two tables that list prospective and actual customers, a third that lists vendors from whom you purchase supplies, and you want to create a single mailing list by merging names and addresses from all three tables. UNION provides a way to do this. Assume the three tables have the following contents:
http://w3webtutorial.blogspot.com/2013/11/union-in-mysql.html
You are doing the union before and then applying the where clause. So you would get a unique combination of "requester_name,receiver_name" and then the where clause would apply. Apply the where clause in each select...
Select requester_name,receiver_name from poem_authors_follow_requests
where (LOWER(requester_name)=LOWER('user1')
or LOWER(receiver_name)=LOWER('user1'))
UNION
Select requester_name,receiver_name from poem_authors_friend_requests
where (LOWER(requester_name)=LOWER('user1')
or LOWER(receiver_name)=LOWER('user1'))
In your where statement, reference the alias "u" for each field refence in your where statement.
So the beginning of your where statement would be like: where (LOWER(u.requester_name) = ...
This is simlar to the answer you can see in: WHERE statement after a UNION in SQL?
You should be able to use the INTERSECT keyword instead of doing a nested query on a UNION.
SELECT member_id, name FROM a
INTERSECT
SELECT member_id, name FROM b
can simply be rewritten to
SELECT a.member_id, a.name
FROM a INNER JOIN b
USING (member_id, name)
http://www.bitbybit.dk/carsten/blog/?p=71