Using UNION in a query with PHP - php

I have an SQL query which links 3 tables using UNION:
$sql ="(SELECT Drive.DriveID,Ram.Memory from Drive,Ram where Drive.DriveID = Ram.RamID) UNION
(SELECT Drive.DriveID,External.Memory from Drive, External where Drive.DriveID = External.ExtID)";
Suppose I want to get Ram.Name as well. How do I do this? If I use Ram.Name in the first SELECT statement it would not produce the correct result.
Any method for tackling this? I want to do it using UNION.

In a Union query, all of the columns must be specified in all of the statements in the same order.
Therefore you'd need to have
(SELECT Drive.DriveID,Ram.Memory,Ram.Name
from Drive,Ram
where Drive.DriveID = Ram.RamID)
UNION
(SELECT Drive.DriveID,External.Memory, '' as Name
from Drive, External
where Drive.DriveID = External.ExtID)
Or if your External table has a Name field you could Include that one instead of an empty string.

Related

SQL How to find missing values in rows

I have a database and an external file. What these two share are reference codes for products.
But in the external file I have all my reference codes saved down, whilst plenty are still missing in the database. Is there a way to make a query so that I can check what values are missing in my database, in a given table?
There's no need to worry about how the XML interfaces with the database. I already have that down through PHP and simplexml. I am mostly struggling with the query to use in this case.
Database
XML File
AJS2S
AJS2S
ABBB2
ABBB2
JJI90K
JJJJ92
If you have a list of valus at hand and you want to check which ones are missing in your table, you enumerate them in a union all subquery, then use not exists:
select x.product_code
from (
select 'AJS2S' as product_code
union all select 'ABBB2'
union all ...
) x
where not exists (select 1 from mytable t where t.product_code = x.product_code)
Or, in very recent versions of MySQL (8.0.19 or higher), you can use the values() row constructor:
select x.product_code
from (values row('AJS2S'), row('ABBB2'), ...) x(product_code)
where not exists (select 1 from mytable t where t.product_code = x.product_code)
Of course, if you have your xml data already loaded in a table, say xmltable, then you can use that instead of the subquery:
select x.product_code
from xmltable x(product_code)
where not exists (select 1 from mytable t where t.product_code = x.product_code)
You would use not exists:
select code
from xml
where not exists (select 1 from database d where d.code = xml.code);
This retrieves each code -- so it might have many duplicates. You can summarize using group by:
select code, count(*)
from xml
where not exists (select 1 from database d where d.code = xml.code)
group by code;

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 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);

MySQL - selecting from multiple tables, possibly without joins?

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.

SELECT COUNT(DISTINCT name), id, adress from users

With PHP I'm trying to run a SQL query and select normal columns as well as COUNT.
$sql_str = "select COUNT(DISTINCT name), id, adress from users";
$src = mysql_query($sql_str);
while( $dsatz = mysql_fetch_assoc($src) ){
echo $dsatz['name'] . "<br>";
}
The problem is that when I have "COUNT(DISTINCT name)," in my query, it will only return the first entry. When I remove it, it will return all matching entries from the db.
I could separate it and do 2 queries, but I'm trying to avoid this due to performance concerns.
What do I make wrong?
thx, Mexx
The ability to mix normal columns and aggregate functions is a (mis)feature of MySQL.
You can even read why it's so dangerous on MySQL's documentation:
https://dev.mysql.com/doc/refman/5.6/en/group-by-extensions.html
But if you really want to mix normal rows and a summary in a single query, you can always use the UNION statement:
SELECT COUNT(DISTINCT name), null, null FROM users GROUP BY name --summary row
UNION
SELECT name, id, address FROM users --normal rows
COUNT() is an aggregate function, it aggregates against the results of the rest of your query. If you want to count all distinct names, and not just the distinct names associated with the id and address that you are selecting, then yes, you will have to run two queries. That's just how SQL works.
Note that you should also have a group by clause when aggregating. I think the fact that MySQL doesn't require it is horrible, and it encourages really bad habits.
From what I understand, you want to get :
one line per user, to get each name/id/address
one line for several users at the same time, to get the number of users who have the same name.
This is not quite possible, I'd say.
A solution would be, like you said, two queries...
... Or, in your case, you could do the count on the PHP side, I suppose.
ie, not count in the query, but use an additionnal loop in your PHP code.
When you have a count() as part of the field list you should group the rest of the fields. In your case that would be
select count(distinct name), id, adress from users group by id, adress
select count(distinct name), id, adress
from users
group by id, adress
I'm assuming you want to get all your users and the total count in the same query.
Try
select name, id, address, count(id) as total_number
from users
group by name, id, address;

Categories