MySQL - selecting from multiple tables, possibly without joins? - php

It's been a while since I needed help, but today I'm here to basically get assistance from your knowledge. I'm currently quite stuck on a very annoying SQL problem, which is the following.
I have two tables. Painteditems, and specialitems. Both tables have unique column names (painteditemid, specialitemid etc), yet both tables share similar values. I want to get results from both tables.
Let's say this is my setup:
PaintedItems
paintedItemName
paintedItemColor
visible
SpecialItems
specialItemName
specialItemColor
visible
I used this query:
SELECT *
FROM `painteditems` AS pa,
`specialitems` AS sp
WHERE (pa.`visible` = 1
OR sp.`visible` = 1)
AND (pa.`painteditemname` = 'itemname1'
OR sp.`specialitemname` = 'itemname1')
AND (pa.`painteditemcolor` = 'black'
OR sp.`specialitemcolor` = 'black')
That resulted in:
Showing rows 0 - 29 ( 259,040 total, Query took 39.4352 sec)
even though both tables contain only 10.000 rows altogether. Adding this did nothing:
GROUP BY pa.`painteditemid`, sp.`specialitemid`
Still 260k rows. How should I approach this?
Thank you in advance.
edit: fixed spacing, code blocks

Sure sounds like you want a UNION between the two tables. Right now, you are getting a cartesian product which is why the results are so large:
select *, 'painted' Source
from painteditems
where visible = 1
and painteditemname = 'itemname1'
and painteditemcolor = 'black'
union all
select *, 'special' Source
from specialitems
where visible = 1
and specialitemname = 'itemname1'
and specialitemcolor = 'black'
You will need to replace the SELECT * with your column names. Also the number of columns and datatypes must match in both queries.
UNION ALL will return all rows from both tables, if you only want DISTINCT rows then you will want to use UNION

The UNION operator is used to combine the result-set of two or more SELECT statements. Defiantly You can make use of UNION as shown in the #bluefeet's answer If you meet below conditions.
SELECT statement within the UNION must have the same number of
columns
The columns must also have similar data type
The columns in each SELECT statement must be in the same order.

I would do this with a union all in the subquery:
select *
from ((select paintedItemName as ItemName, paintedItemColor as ItemColor, visible, 'Painted' as which
from painteditems
) union all
(select specialItemName, SpecialItemColor, visible, 'Special' as which
from specialitems
)
) t
where visible = 1 and itemname = 'itemname1' and itemcolor = 'black'
This allows you to have only one set of results. In a union, the column names come from the first subquery, which this renames to more generic names. The reason I prefer this approach is because the where clause does not need to be repeated multiple times -- which can lead to errors and maintenance problems.

Related

MYSQL/PHP - Select all columns from table records distincting by one column

I'm a bit confused about DISTINCT keyword. Let's guess that this query will get all the records distincting the columns set in the query:
$query = "SELECT DISTINCT name FROM people";
Now, that query is fetching all the records distincting column "name" and at the same time only fetching "name" column. How I'm supposed to ONLY distinct one column and at the same time get all the desired columns?
This would be the scheme:
NEEDED COLUMNS
name
surname
age
DISTINCTING COLUMNS
name
What would be the correct sintaxis for that query? Thanks in advance.
If you want one row per name, then a normal method is an aggregation query:
select name, max(surname) as surname, max(age) as age
from t
group by name;
MySQL supports an extension of the group by, which allows you to write a query such as:
select t.*
from t
group by name;
I strongly recommend that you do not use this. It is non-standard and the values come from indeterminate matching rows. There is not even a guarantee that they come from the same row (although they typically do in practice).
Often, you want something like that biggest age. If so, you handle this differently:
select t.*
from t
where t.age = (select max(t2.age) from t t2 where t2.name = t.name);
Note: This doesn't use group by. And, it will return duplicates if there are multiple rows with the same age.
Another method uses variables -- another MySQL-specific feature. But, if you are still learning about select, you should probably wait to learn about variables.

How get table with references other table in yii2?

i have multiple table that join together and i need one query and get all references too ! is that possible in yii2??
get them in hierarchy array ??
How ???
Is it possible to do not use join???
thanks for your help!!!!
If you created the model classes for each table using Gii and selected to create the relations in the generated models, you can do something like the following.
1) In your Countries model just change the method that declares the relationship with Airports like this:
public function getAirports() {
return $this->hasMany(Airports::className(), ['country_id' => 'id'])->with('airlines');
}
2) When you do the query for the countries and you need to have the related airports, airlines and flightbooked do it like this:
$countries = Countries::find()
->where('something = something_else')
->with('airports')
->with('flightbooked')
->all();
This way you will get all the related models populated with way less queries to the database than using lazy-loading.
I just wanted to give a small suggestion:
As you are maintaining the relations in the tables and if you have generated your code using Gii, then that will generate the joins for you. You can then access any column of any table easily.
But I think UNION may not be an alternative to JOIN.
Maybe u can use union all for this. with this operator, you can concatenate the result sets from multiple queries together, preserving all of the rows from each. Note that a UNION operator (without the ALL keyword) will eliminate any "duplicate" rows which exist in the resultset. The UNION ALL operator preserves all of the rows from each query (and will likely perform better since it doesn't have the overhead of performing the duplicate check and removal operation).
The number of columns and data type of each column must match in each of the queries. If one of the queries has more columns than the other, we sometimes include dummy expressions in the other query to make the columns and datatypes "match". Often, it's helpful to include an expression (an extra column) in the SELECT list of each query that returns a literal, to reveal which of the queries was the "source" of the row.
SELECT 'col1' AS source, col23, col343, col33, d FROM table1 WHERE ...
UNION ALL
SELECT 'col2', t2.fee, table2.fi, table2.fo, 'fum' FROM table2 JOIN table3 ON ...
UNION ALL
SELECT 'col3', '1', '2', buckle, my_shoe FROM table4
You can wrap a query like this in a set of parenthesis, and use it as an inline view (or "derived table", in MySQL lingo), so that you can perform aggregate operations on all of the rows. e.g:
select one.a
, SUM(one.b)
FROM (
SELECT 'q1' AS source, a, b, c, d FROM t1
UNION ALL
SELECT 'q2', t2.fee, t2.fi, t2.fo, 'fum' FROM t2
) one
GROUP BY one.a
ORDER BY one.a
But i think joining tables more suitable. Hope help you

How to get results from multiple tables using a single query in CodeIgniter?

I have a situation where i need to get data from 7 different tables for a particular processing to be performed.
I will need 7 simple SELECT all statements, nothing fancy. But to minimize the database hit, I will very much like to bundle these queries into 1 or 2 queries.
Like:
select * from table1; select * from table2; select * from table3;.
And will call this query from my code. Is is possible to get the results in something on the similar lines of .net's DataSet in PHP. I am looking for a solution in core PHP or CodeIgniter. I am using PDO for database connection.
PS: The tables have different schemas, no common point. So any solution with join or union will not work.
$results = $this->db-query("select * from tb1; select * from tb2");
now $result[0] should have all the records from tb1 and $results[1] should have the records from tb2.
Something on the similar line will be most helpful in this scenario.
Look into InnerJoin. That's how you make multiple selections at once - assuming you have a common data point
What you need is UNION
$this->db->query('SELECT column_name(s) FROM table_name1 UNION ALL SELECT column_name(s) FROM table_name2');
UNION ALL This is the UNION keyword, and the optional ALL keyword. UNION indicates that the results of the SELECT statement that precedes UNION will be combined with the results of the SELECT statement that follows UNION.
When you use the ALL keyword, duplicate rows are not removed from the combined set that is produced by the union. This can dramatically improve the performance of the query, because Access does not have to check the results for duplicate rows. You should use the ALL keyword if any of the following conditions is true:
You are certain that the select queries will not produce any
duplicate rows.
It does not matter if your results have duplicate rows.
You want to see duplicate rows.
EDITED
After your edition and what I've got it from your question then this might be helpful. You need to loop that queries to get an array of results as
$tablename = array('name1','name2','name3','name4','name5','name6','name7');
$results = array();
foreach($tablename as $key => $value){
$results[$key] = $this->db->query("select * from ".$value."")->result_array();
}
Multiple select query in codigniter
$this->db->select('t1.*, t2.*');
$this->db->from('table1 AS t1, table2 AS t2');
$query = $this->db->get();
$row = $query->result_array();
print_r($row);

How do I search multiple mySQL tables to find one specific row?

I have three tables: adapters, connectors, components
I need to be able to search them all to find a corresponding Part Number (part_num)
The part number is unique so I don't have to worry about multiple entries.
I use GET to find the part number in the URL, set it to $num, and then do the SELECT
What I've found is that I should use UNION, however the three tables have different columns and it gives me an error when trying to do the select. In the example below
Using UNION to find references from other tables
This is my code:
if(isset($_GET['num'])) {
$num = $_GET['num'];
$result = mysql_query("SELECT * FROM connectors WHERE part_num = '$num' UNION SELECT * FROM adapters WHERE part_num = '$num' UNION SELECT * FROM components WHERE part_num = '$num'"); }
Any help would be appreciated, so thanks in advance SO =)
You should probably have a fourth table Parts that identifies to which type table each part_num has been allocated. However, without that, you could still get what you're after with outer joins (wasteful though):
SELECT * FROM
connectors
LEFT JOIN adapters USING(part_num)
LEFT JOIN components USING(part_num)
WHERE
part_num = ?
Note that I have used ? as you really should be using prepared statements: if you don't know why, or what they are, read about Bobby Tables.
How about taking not all columns, but only titles or so on?
$sSql = "SELECT id, title, 1 FROM connectors WHERE part_num = '$num'
UNION
SELECT id, title, 2 FROM adapters WHERE part_num = '$num'
UNION
SELECT id, title, 3 FROM components WHERE part_num = '$num'";
You must adopt it to your table fields, but with this logic you will have an array where by the Third column (in my example), you can know if it is connector, adapter or component found, then generate proper links or do other actions with this data.
Another Way is to make Multi query, which will return multiple results by one database request. There are some ways to use it - using mysqli (http://lt.php.net/manual/en/mysqli.multi-query.php) or some of Adodb or PDO libraries.
Hope it will help.
To use UNION, the 3 recordsets must have the same number of columns, so you'll have to specifed which columns from each table that you want. From there, you'll have a single results set with the data from each of the 3 queries.

Apply a limit of 10 after taking distinct records in mysql

In a MySQL table, I would like to take 10 records with DISTINCT values.
I am using Zend Framework.
$select = $this->getAdapter()->select()
->from('table', 'column')->group('column')
->limit(10, 0);
This is the query generated by the above code.
SELECT table.column FROM
table GROUP BY column LIMIT 10
What happens here is that MySQL is taking 10 records first and then applying the group by. So finally, I am getting only 7 records.
How to apply DISTINCT first and then take 10 records from it?
Test that SQL against a table -- MySQL applies the limit last, so doesn't do what you're saying. eg test against
a0 a1
1 1
2 1
3 2
4 2
and do select A.a1 from A group by a1 limit 2. You should see 1, 2, not 1, 1.
[I wanted to say this as a 'comment' rather than an 'answer', but couldn't]
I'm not 100% sure what you are trying to do.
But if i am reading it correct you need 10 records with a certain criteria and then apply the group. not the other way around.
Can't you use WHERE in this case?
SELECT table.column FROM table WHERE "criteria" GROUP BY column LIMIT 10
Regards
Mike
This may help you (I didn't test it but so I'm not sure it's working)
SELECT DISTINCT column FROM table LIMIT 10
If it's not working, you may use a temporary table (like (SELECT column FROM table) TEMP), which will select the distinct elements, then a query which will select the first ten results into this table.
Hope this'll help :)
In ZF, You should use distinct() method into Your query chain :
$select = $this->getAdapter()->select()
->distinct()
->from('table', 'column')
->limit(10, 0);
SELECT DISTINCT column
FROM table
LIMIT 10
GROUP BY column
Not sure how to get it into classes though...

Categories