UNION ALL | Merge 2 queries that have the same column and table - mysql

I need to merge to queries together. This is a simple task that I do a lot, but this time I have something a little bizarre. The 2 queries I'm merging are from the same table and the same column.
Here is a basic concept of my original table:
|id|content|
0 | a
1 | b
2 | c
3 | d
I want my query to return everything once. Then again where I selected it. So SELECT * FROM 'my_table' and SELECT * FROM 'my_table WHERE id IN (1,2) I want it to return something like this.
a
b
a
b
c
d
Edit: #dnoeth commented the right answer. I didn't read it right the first time though.

I found the answer I was looking for. I just didn't know how to word was I was looking for.
What I needed to do was unite 2 queries on the same table.
You do this by simply using UNION ALL instead of union
So here is an example in mysql.
SELECT * FROM my_table UNION ALL SELECT * FROM my_table WHERE id IN (1,2)
Then if you are using Laravel's eloquent like I am use this.
$query = Class::whereIn('id', $array);
Class::where('id','>=',0)->unionAll($query)->get();

Well since you're not really precise on what the result should be, you might do like this:
select t1.val
from tableT t1
join tableT t2 on t1.id=t2.id or t1.id+1=t2.id
where t1.id<=2 and t2.id<=2 or t1.id>=3
Should yield:
a
b
b
c
c
d

Just use the clause UNION, you can "join" several SELECTs with the only restiction that they have same result columns. Your example will be:
(SELECT * FROM 'my_table')
UNION
(SELECT * FROM 'my_table WHERE id IN (1,2))
And you will get:
|id|content|
0 | a
1 | b
2 | c
3 | d
1 | b
2 | c
More details:
http://dev.mysql.com/doc/refman/5.7/en/union.html
PS:
The default behavior for UNION is that duplicate rows are removed from the result. With the optional ALL keyword, duplicate-row removal does not occur and the result includes all matching rows from all the SELECT statements.

Related

how to convert rows to column based type filter without using sub-query

I've large data which could be filtered on type column. I can get rows data using subquery with self-join and transform to the column, but due to large data, it would take a lot of time using a subquery. My table structure is like:
Table A
Id | ItemName | Type
1 | Item1 | A
2 | Item2 | A
3 | Item3 | B
4 | Item4 | B
Table B
Id | ItemDescTag | Ext
1 | ItemTag | A
4 | ItemTag | B
Query
Select ItemName,PurchaseOrdr.Quantity, PurchaseOrdr.PORate, PurchaseOrdr.CostAmount
from TableA its
left join (
select it.Id, it.Quantity,(it.CostAmount/it.Quantity)as PORate, it.CostAmount from TableA it
inner join Table B m on it.Type = convert(int ,m.Ext)
)as PurchaseOrdr on PurchaseOrdr.Id = its.Id
I need an alternate way to get rid of this SUB-QUERY because I have to make 10 SUB-QUERY of a similar type to get the required data and due to millions of records it slows down ...
Depending on how similar the other 10 sub-queries are you could query the columns needed ahead of time in CTE like
;WITH PurchaseOrdr_CTE AS(
SELECT
it.Id,
it.Quantity,
it.CostAmount
FROM TableA it
JOIN TableB m
ON it.Type = convert(int ,m.Ext)
)
SELECT
ItemName,
PurchaseOrdr.Quantity
, (PurchaseOrdr.CostAmount/PurchaseOrdr.Quantity) AS PORate,
PurchaseOrdr.CostAmount
FROM TableA its
LEFT JOIN PurchaseOrdr_CTE PurchaseOrdr
ON its.Id = PurchaseOrdr.Id
In this particular example I don't see the need to reference TableA twice at all. But the actual query you are using might have additional columns, logic not included in the post.
The it.Type = convert(int ,m.Ext) conversion will have some overhead. If it's possible to use consistent data types that's obviously better.
If you are dealing with millions of records and this will be an important query, a good covering index will have a large impact.

mysql select twice itself again in one table

How to select in 1 query below. This query need re search that's find value to their own loop.
This is different from other sub query , using 1 table only
TAble T
| num| WHOSE
| 1 | A
| 1 | C
| 2 | B
| 2 | C
| 3 | D
Criteria to match records (conditions):
The value in column whose is not C
The value in column num does not match a value for another record in condition 1.
I want to find the record the value 3 in column num (which has D for column whose).
select * from T where whose <> C and ( num is not one of c's)
1 A can not because C has 1
2 B can not because C has 2
3 D is what I want, because it doesn't have C in column whose nor share a value in column num with a record that does have C in the column whose.
First select num of those records where whose is C. Then select those records where whose is not C and also where num is not one of the ones in subquery.
Select * from T where whose <> 'C' and num not in (Select Num from T where whose = 'C' )
Another way to achieve the same result is with a LEFT JOIN on the same table:
SELECT T.*
FROM T
LEFT JOIN T t2 on t2.num = T.num and t2.whose = 'C'
WHERE T.whose <> 'C' AND t2.whose IS NULL
Check it out on this SQL Fiddle, where the result is:
| num | whose |
| 3 | D |
Additionally, a similar way to write the query is to use the NOT EXISTS clause in the WHERE conditions, like this:
SELECT T.* from T
WHERE T.whose <> 'C' AND NOT EXISTS (SELECT 1 FROM T t2 WHERE
t2.num = T.num AND t2.whose = 'C')
Check it out in this SQL fiddle.
To read more about the comparison between EXISTS and LEFT JOIN see this article. In the summary at the end it has the following conclusions:
MySQL can optimize all three methods to do a sort of NESTED LOOPS ANTI JOIN.
...
However, these three methods generate three different plans which are executed by three different pieces of code. The code that executes EXISTS predicate is about 30% less efficient than those that execute index_subquery and LEFT JOIN optimized to use Not exists method.
That's why the best way to search for missing values in MySQL is using a LEFT JOIN / IS NULL or NOT IN rather than NOT EXISTS.

MySQL query to select rows matching criteria and rows related to the matching rows

I would like to select all rows where a column matches a criteria, but also select all rows that don't match the criteria, but have a relation to the rows that do match the criteria.
Given a table structure like this:
group_id | word
---------+------
1 | the
2 | cat
2 | sat
3 | on
1 | the
3 | mat
Given the criteria WHERE word LIKE '%at%', I'd want to get the matching rows
2 | cat
2 | sat
3 | mat
but I also want to get the related rows. That is, rows with a group_id equalling the group_id of any row matching the criteria, which in this case would be group_id 2 or 3. The final result should be:
2 | cat
2 | sat
3 | on
3 | mat
I think that a self join is the way to go, but I can't quite figure it out.
One method uses in:
select t.*
from t
where t.group_id in (select t2.group_id
from t t2
where t2.word LIKE '%at%'
);
If you try to do the same thing using join, you might get duplicate results.
I think I've figured out how to do it with a self join.
SELECT DISTINCT `t1`.*
FROM `test` AS `t1` JOIN `test` AS `t2`
ON `t1`.`group_id`=`t2`.`group_id`
WHERE `t2`.`text` LIKE '%at%'
I don't know if there is a better (more efficient) way to do this query.
You can join to a derived table that returns all selected group_id values:
SELECT t1.*
FROM mytable AS t1
JOIN (SELECT DISTINCT group_id
FROM mytable
WHERE word LIKE '%at%'
) AS t2 ON t1.group_id = t2.group_id
You have to use DISTINCT in the subquery, so as to be sure that you get one row per group_id, so that the final result doesn't contain any duplicates.

MYSQL Join: find all matches from table a , even if not present in table b

i have a table a:
id | name | ...
1 paul
2 paula
and a table b
id | nameId | active
1 1 1
And try to come up with a query that would result in the following:
id | name | active
1 paul 1
2 paula
Nevermind the fact that the example data does not make much sense please.
My problem is that i need a query that selects all records from table a that match some condition, and finds a certain value for those results in table B, if present, and adds it to the result set, but without omitting those results from table a that have no match in table b.
so far i have tried something like this:
SELECT a.id, a.name, b.active FROM a left join b b.nameId=a.id WHERE (something)
But that gives me only the first row.
Any help would be much appreciated!
Your query should give the desired result, at least minus the mystery WHERE clause:
SELECT a.id,
a.name,
COALESCE(CAST(b.active AS CHAR(50)), 'NA') -- replace NULL with NA
FROM a
LEFT JOIN b
ON a.id = b.nameId
-- WHERE (you can add a WHERE clause, but it might filter off rows)

How do I select row based on the number of times it appears in the table?

I have my table: call it tblA THis table has three rows, id, sub-id, and visibility
sub-id is the primary key (it defines taxonomies for id). I'm trying to build a query that selects every id that appears less than three times.
here is an example query/result
select * from tbla where id = 188002;
+--------+--------+-------------+
| sub-id | id | visibility |
+--------+--------+-------------+
| 284922 | 188002 | 2 |
| 284923 | 188002 | 2 |
| 284924 | 188002 | 0 |
+--------+--------+-------------+
From what i've seen here and here it looks like I need to join the table on...itself. I dont really understand what that accomplishes.
If anyone has insight into this, it is appreciated. I will continue to research it and update this topic with any additional information I come across.
Thanks
SELECT id
FROM tbla
GROUP BY id
HAVING COUNT(*) < 3
If you want to select all columns from the table, you will have to use #Joe's query in a sub-select:
SELECT * FROM tbla a
WHERE a.id IN (SELECT DISTINCT b.id
FROM tbla b
GROUP BY b.id
HAVING COUNT(*) < 3)
This query first selects all id's that have fewer than 3 duplicates.
The distinct eliminates duplicates, the query works the same without, but slightly slower.
Next it selects all rows that have an id that meets the criteria in the sub-select i.e. that have fewer than 3 duplicate id's.
The reason that you cannot do this in one go is that the group by heaps all rows with the same id together into one super-row (for want of a better metafor) .
You cannot separate out the columns that are not in the group by clause.
The outer select solves this.