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

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

Related

How to avoid running an expensive sub-query twice in a union

I want to union two queries. Both queries use an inner join into a data set, that is very intensive to compute, but the dataset query is the same for both queries. For example:
SELECT veggie_id
FROM potatoes
INNER JOIN ( [...] ) massive_market
ON massive_market.potato_id=potatoes.potato_id
UNION
SELECT veggie_id
FROM carrots
INNER JOIN ( [...] ) massive_market
ON massive_market.carrot_id=carrots.carrot_id
Where [...] corresponds to a subquery that takes a second to compute, and returns rows of at least carrot_id and potato_id.
I want to avoid having the query for massive_market [...] twice in my overal query.
Whats the best way to do this?
If that subquery takes more than a second to run, I'd say it's down to an indexing issue as opposed to the query itself (of course, without seeing that query, that is somewhat conjecture, I'd recommend posting that query too). In my experience, 9/10 slow queries issues are down to improper indexing of the database.
Ensure veggie_id, potato_id and carrot_id are indexed
Also, if you're using any joins in the massive_market subquery, ensure the columns you're performing the joins on are indexed too.
Edit
If indexing has been done properly, the only other solution I can think of off the top of my head is:
CREATE TEMPORARY TABLE tmp_veggies (potato_id [datatype], carrot_id [datatype]);
INSERT IGNORE INTO tmp_veggies (potato_id, carrot_id) select potatoes.veggie_id, carrots.veggie_id from [...] massive_market
RIGHT OUTER JOIN potatoes on massive_market.potato_id = potatoes.potato_id
RIGHT OUTER JOIN carrots on massive_market.carrot_id = carrots.carrot_id;
SELECT carrot_id FROM tmp_veggies
UNION
SELECT potato_id FROM tmp_veggies;
This way, you've reversed the query so it's only running the massive subquery once and the UNION is happening on the temporary table (which'll be dropped automatically but not until the connection is closed, so you may want to drop the table manually). You can add any additional columns you need into the CREATE TEMPORARY TABLE and SELECT statement
The goal is to pull all repeated query-strings out of the list of query-strings requiring the repeated query-strings. So I kept potatoes and carrots within one unionizing subquery, and placed massive_market afterwards and outside this unification.
This seems obrvious, but my question originated from a much more complex query, and the work needed to pull this strategy off was a bit more involving in my case. For my simple example in my question above, this would resolve in something like:
SELECT veggie_id
FROM (
SELECT veggie_id, potato_id, NULL AS carrot_id FROM potatoes
UNION
SELECT veggie_id, NULL AS potato_id, carrot_id FROM carrots
) unionized
INNER JOIN ( [...] ) massive_market
ON massive_market.potato_id=unionized.potato_id
OR massive_market.carrot_id=unionized.carrot_id

Merging multiple queries preferentially

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 ...

Learning SQL: UNION or JOIN?

Forgive me if this seems like common sense as I am still learning how to split my data between multiple tables.
Basically, I have two:
general with the fields userID,owner,server,name
count with the fields userID,posts,topics
I wish to fetch the data from them and cannot decide how I should do it: in a UNION:
SELECT `userID`, `owner`, `server`, `name`
FROM `english`.`general`
WHERE `userID` = 54 LIMIT 1
UNION
SELECT `posts`, `topics`
FROM `english`.`count`
WHERE `userID` = 54 LIMIT 1
Or a JOIN:
SELECT `general`.`userID`, `general`.`owner`, `general`.`server`,
`general`.`name`, `count`.`posts`, `count`.`topics`
FROM `english`.`general`
JOIN `english`.`count` ON
`general`.`userID`=`count`.`userID` AND `general`.`userID`=54
LIMIT 1
Which do you think would be the more efficient way and why? Or perhaps both are too messy to begin with?
It's not about efficiency, but about how they work.
UNION just unions 2 different independent queries. So you get 2 result sets one after another.
JOIN appends each row from one result set to each row from another result set. So in total result set you have "long" rows (in terms of amount of columns)
Just for completeness as I don't think it's mentioned elsewhere: often UNION ALL is what's intended when people use UNION.
UNION will remove duplicates (so relatively expensive because it requires a sort). This remove duplicates in the final result (so it doesn't matter if there's a duplicate in a single query or the same data from individual SELECTs). UNION is a set operation.
UNION ALL just sticks the results together: no sorting, no duplicate removal. This is going to be quicker (or at least no worse) than UNION.
If you know the individual queries won't return duplicate results use UNION ALL. (In fact often best to assume UNION ALL and think about UNION if you need that behaviour; using SELECT DISTINCT with UNION is redundant).
You want to use a JOIN. Joining is used to creating a single set which is a combination of related data. Your union example doesn't make sense (and probably won't run). UNION is for linking two result sets with identical columns to create a set that has the combined rows (it does not 'union' the columns.)
If you want to fetch users and near user posts and topics. you need to write QUERY using JOIN like this:
SELECT general.*,count.posts,count.topics FROM general LEFT JOIN count ON general.userID=count.userID

SELECT command in mysql

I was wondering if there is a way to do something like selecting all without ... some columns here
something like SELECT */column1,column2 , is there a way to do this ?
I just need to output something like
column1 , column2 ( from another table ) , here all other columns without column1 ( or something to make the select skip the first few columns)
EDIT:
The thing is that i need this to be dynamic , so i cant just select what i don't know. I never know how many columns there will be , i just know the 1st and the 2nd column
EDIT: here is a picture http://oi44.tinypic.com/xgdyiq.jpg
I don't need the second id column , just the last column like i have pointed.
Start building custom views, which are geared aorund saving developers time and encapsulating them from the database schema.
Oh, so select all but certain fields. You have two options.
One is a little slow.. Copy the table, drop the fields you don't want, then SELECT *
The other is to build the field list from a subquery to information_schema or something, then remove occurrences of 'field_i_dont_want' in that list.
SELECT ( SELECT THE TABLES YOU WANT AND CONCAT INTO ONE STRING ) FROM TABLE
If you need to combine records from multiple tables, you need to find a way to relate them together. Primary Keys, Foreign Keys, or anything common among this.
I will try to explain this with a sql similar to your problem.
SELECT table1.id, table2.name, table1.column3, table1.column4
FROM table1
INNER JOIN table2 On table2.commmonfield = table1.commonfield
If you have 'n' columns in your table as in Col1,Col2,Col3....Coln you can select whatever columns you want to select from the table.
SELECT Col1,Col2 FROM YOURTABLE;
You either select all columns (*) or especify the columns you want one by one. There is no way to select 'all but some'.
The SQL language lets you either select a wildcard set of columns or enumerated single columns from a singular table. However you can join a secondary table and get a wildcard there.
SELECT
a.col1,
b.*
FROM
table_a as a
JOIN table_b as b ON (a.col5 = b.col_1)

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