Using 1st SQL select statement results for 2nd select statement - php

I'd like some help combining Multiple SQL queries into one...
I have a search box for orderid or sampleref. An order may have up to 99 sampleref in it so I want the customer to be able to pull up a list of all sampleref associated with their order number regardless of if they search by orderid or one of their sampleref. Essentially what I want to do is,
SELECT `orderid` as OrderNumber FROM `results` WHERE `sampleref` = 'TEST12345';
SELECT * FROM `results` WHERE `orderid` = OrderNumber GROUP BY `sampleref`;
For clarity I'm putting this into a PHP script for a Maria DB mysql server
Here is a sample database
+----+---------+-----------+
| id | orderid | sampleref |
+----+---------+-----------+
| 1 | 101388 | TEST12345 |
| 2 | 101388 | TEST54321 |
| 3 | 333444 | ABC123 |
| 4 | 333444 | ABC321 |
+----+---------+-----------+
Thanks
Henry

Following will give you what you are looking for.
select r2.orderid, r2.sampleref
from result r
join result r2 on r.orderid = r2.orderid
where r.sampleref = 'TEST12345' or r.orderid = <orderid>

You can use or with a correlated subquery:
SELECT r.*
FROM results r
WHERE r.orderid = $orderid OR
EXISTS (SELECT 1
FROM results r2
WHERE r2.orderid = r.orderid AND r2.sampleref = $sampleref
);
Note: This takes two parameters -- either the order id or the sample ref. The first condition returns everything with the same order, if that is given. The second returns everything with the same order as the given sample ref.

Related

SQL need to improve run speed

I am trying to select data from mysql by a date field in the database. (Users can enter start date and end date)
For each selected row between user selected dates, I need to select from the same table to produce a result.
Example:
$query = "SELECT * FROM table WHERE date BETWEEN $begindate AND $enddate"; //Select by date
$result = mysqli_query($dbc,$query);
while($row = mysqli_fetch_array($result)){
vardump($row); //user needs to see all data between date selection
$query = "SELECT * FROM table WHERE field = $row['field']";
// and then do calculations with the data
}
This runs very slowly and I can see why. How can I improve the run speed?
Edit:
The original purpose was to generate a sales report between dates. Now the user wants the report to produce another result. This result could only be produced by searching against the same table, and the rows that I need is not within the date selection.
Edit 2:
I do need to output the entire table between date selection. Each row will need to find ALL other rows where field = field, within or out side of the date selection.
Edit 3: Solved the problem. All the answers are helpful, though I think the chosen answer was most related to my question. However, I believe using join when working with two tables is the right way to go. For my problem, I actually just solved it by duplicating the table and run my search against the duplicated table. The chosen answer did not work for me because the second query selection is not a part of the first query selection. Hope this would help anyone looking at this post. Again, thanks for all the help!
Well, so if you are really looking for such a conditions in same table, I suggest you should use IN selector like following:
$query = "SELECT * FROM table
WHERE field IN
(SELECT DISTINCT field FROM table
WHERE
date BETWEEN $begindate AND $enddate)";
So final code will look some like following:
$query = "SELECT * FROM table
WHERE field IN
(SELECT DISTINCT field FROM table
WHERE
date BETWEEN $begindate AND $enddate)";
$result = mysqli_query($dbc,$query);
while($row = mysqli_fetch_array($result)){
// do calculations with the $row
}
I guess your table names arent TABLE:
just user inner join
$query = "SELECT *
FROM table1
JOIN table2
ON table1.field = table2.field
WHERE date BETWEEN $begindate AND $enddate
ORDER BY table1.field;"
Stop writing pseudo-SQL
SELECT * FROM is technically pseudo-SQL (a sql command which the interpreter has to modify before the command can be executed. It is best to get in a habit of specifying columns in the SELECT statement.
Use SQL joins
Joins are what makes relational databases so useful, and powerful. Learn them. Love them.
Your set of SQL queries, combined into a single query:
SELECT
table1.id as Aid, table1.name as Aname, table1.field as Afield,
table2.id as Bid, table2.name as Bname, table2.field
FROM table table1
LEFT JOIN table table2
ON table1.field = table2.field
WHERE table1.date BETWEEN $begindate AND $enddate
ORDER BY table1.id, table2.id
Your resulting print of the data should result in something which access each set of data akin to:
$previous_table1_id = 0;
while($row = mysqli_fetch_array($result)){
if ($row['Aid'] != $previous_table1_id) {
echo 'Table1: ' . $row['Aid'] . ' - ' . $row['Aname'] . ' - '. $row['Afield'] . "\n";
$previous_table1_id = $row['Aid'];
}
echo 'Table2: ' . $row['Bid'] . ' - ' . $row['Bname'];
}
Dealing with aggregated data
Data-aggregation (multiple matches for table1/table2 on field), is a complex subject, but important to get to know. For now, I'll leave you with this:
What follows is a simplified example of one of what aggregated data is, and one of the myriad approaches to working with it.
Contents of Table
id | name | field
--------------------
1 | foos | whoag
2 | doh | whoag
3 | rah | whoag
4 | fun | wat
5 | ish | wat
Result of query I gave you
Aid | Aname | Afield | Bid | Bname
----------------------------------
1 | foos | whoag | 1 | foos
1 | foos | whoag | 2 | doh
1 | foos | whoag | 3 | rah
2 | doh | whoag | 1 | foos
2 | doh | whoag | 2 | doh
2 | doh | whoag | 3 | rah
3 | rah | whoag | 1 | foos
3 | rah | whoag | 2 | doh
3 | rah | whoag | 3 | rah
4 | fun | wat | 4 | fun
4 | fun | wat | 5 | ish
5 | ish | wat | 4 | fun
5 | ish | wat | 5 | ish
GROUP BY example of shrinking result set
SELECT table1.id as Aid, table1.name as Aname
group_concat(table2.name) as field
FROM table table1
LEFT JOIN table table2
ON table1.field = table2.field
WHERE table1.date BETWEEN $begindate AND $enddate
ORDER BY table1.id, table2.id
GROUP BY Aid
Aid | Aname | field
----------------------------------
1 | foos | foos,doh,rah
2 | doh | foos,doh,rah
3 | rah | foos,doh,rah
4 | fun | fun, ish
5 | ish | fun, ish

Single Query to fetch records from multiple tables with different columns

I have 2 different tables as want to get records in a single query. Currently, I am using 2 queries then merging the array result and then displaying the record. Following is my current code:
$db = JFactory::getDbo();
$query1 = "SELECT a.id as cId, a.title, a.parent_id,a.level FROM `categories` AS a WHERE ( a.title LIKE '%keyword%' )";
$result1 = $db->setQuery($query1)->loadObjectlist(); //gives selected records
$query2 = "SELECT b.id as indId, b.indicator , b.cat_id, b.subcat_id, b.section_id FROM `indicator` as b WHERE ( b.indicator LIKE '%keyword%' )";
$result2 = $db->setQuery($query2)->loadObjectlist(); //gives selected records
$_items = array_merge($result1,$result2); //then using $_items in php code to display the data
It is in Joomla however I just want to know how we can merge these 2 queries into one. I tried the following but it gives the result of first query from categories table.
(SELECT id as cId, title, parent_id,level, NULL FROM `categories` WHERE ( title LIKE '%birth%' ))
UNION ALL
(SELECT id as indId, indicator , cat_id, subcat_id, section_id FROM `indicator` WHERE ( indicator LIKE '%birth%' ))
Desired output:
+------+-------------+------------+--------+--------+----------------+--------+-----------+----------+
| cId | title | parent_id | level | indId | indicator | cat_id | subcat_id | section_id
+------+-------------+------------+--------+--------+----------------+--------+-----------+----------+
| 2874 | births | 2703 | 2 | null | null | null | null | null |
+------+-------------+------------+--------+--------+----------------+--------+-----------+----------+
| 13 | birth weight| 12 | 3 | null | null | null | null | null |
+------+-------------+------------+--------+--------+----------------+--------+-----------+----------+
| null | null | null | null | 135 | resident births| 23 | 25 | 1 |
+------+-------------+------------+--------+--------+----------------+--------+-----------+----------+
| null | null | null | null | 189 | births summary | 23 | 25 | 1 |
+------+-------------+------------+--------+--------+----------------+--------+-----------+----------+
This above output will help to get proper pagination records. I tried to use join but JOIN needs a common column in ON clause. Here, I want all the columns and their values. Basically I want to combine the 2 table records in one query. Any help would be appreciated
Here is an example,
There are a number of ways to do this, depending on what you really want. With no common columns, you need to decide whether you want to introduce a common column or get the product.
Let's say you have the two tables:
parts: custs:
+----+----------+ +-----+------+
| id | desc | | id | name |
+----+----------+ +-----+------+
| 1 | Sprocket | | 100 | Bob |
| 2 | Flange | | 101 | Paul |
+----+----------+ +-----+------+
Forget the actual columns since you'd most likely have a customer/order/part relationship in this case; I've just used those columns to illustrate the ways to do it.
A cartesian product will match every row in the first table with every row in the second:
> select * from parts, custs;
id desc id name
-- ---- --- ----
1 Sprocket 101 Bob
1 Sprocket 102 Paul
2 Flange 101 Bob
2 Flange 102 Paul
That's probably not what you want since 1000 parts and 100 customers would result in 100,000 rows with lots of duplicated information.
Alternatively, you can use a union to just output the data, though not side-by-side (you'll need to make sure column types are compatible between the two selects, either by making the table columns compatible or coercing them in the select):
> select id as pid, desc, '' as cid, '' as name from parts
union
select '' as pid, '' as desc, id as cid, name from custs;
pid desc cid name
--- ---- --- ----
101 Bob
102 Paul
1 Sprocket
2 Flange
In some databases, you can use a rowid/rownum column or pseudo-column to match records side-by-side, such as:
id desc id name
-- ---- --- ----
1 Sprocket 101 Bob
2 Flange 101 Bob
The code would be something like:
select a.id, a.desc, b.id, b.name
from parts a, custs b
where a.rownum = b.rownum;
It's still like a cartesian product but the where clause limits how the rows are combined to form the results (so not a cartesian product at all, really).
I haven't tested that SQL for this since it's one of the limitations of my DBMS of choice, and rightly so, I don't believe it's ever needed in a properly thought-out schema. Since SQL doesn't guarantee the order in which it produces data, the matching can change every time you do the query unless you have a specific relationship or order by clause.
I think the ideal thing to do would be to add a column to both tables specifying what the relationship is. If there's no real relationship, then you probably have no business in trying to put them side-by-side with SQL.
As #Sinto suggested the answer for union and dummy column names following is the whole correct query:
(SELECT id as cId, title, parent_id,level, NULL as indId, NULL as indicator , NULL as cat_id, NULL as subcat_id, NULL as section_id FROM `jm_categories` WHERE ( title LIKE '%births%' )) UNION ALL (SELECT NULL as cId, NULL as title, NULL as parent_id,NULL as level, id as indId, indicator , cat_id, subcat_id, section_id FROM `jm_indicator_setup` WHERE ( indicator LIKE '%births%' ))
We have to match the column names from both tables so that we get records as a combination.

MYSQL left join if then statement favorite table procedure

i have 2 tables
here is table 1 table name is
forexample
itemlist
+-----+----------+-----+
| uid | username | age |
+-----+----------+-----+
| 1 | doe | 17 |
| 2 | smith | 18 |
| 3 | john | 30 |
+-----+----------+-----+
and other one is
fav
+-----+------+---------+
| uid | user | itemuid |
+-----+------+---------+
| 1 | alex | 2 |
+-----+------+---------+
Here is my mysql query *NOT Working * any way to fix this problem when i run php file i got error in mysql syntax
SELECT c.uid, c.username, c.age,i.uid,i.user,i.itemuid
from itemlist c
left join fav i on c.uid = i.itemuid
if (i.user = 'alex') THEN
SET #fav = 1;
ELSE
SET #fav = 0;
END IF
this is sample php
while ($row = mysqli_fetch_array($res)){
if ($row['fav'] = '1'){
echo $row['username']." is exit in fav";
}else{
echo $row['username']." is not exit in fav";
}
}
i hope you understand my question right ?
To get a column named fav returned in the resultset, you would need to include an expression in the SELECT list, and give it an alias fav.
It's not at all clear why you would need a MySQL user-defined variable; if you don't know why you'd need one, then you probably don't need one.
Given that your PHP code is looking for a column named fav in the resultset, likely you want something like this:
SELECT c.uid
, c.username
, c.age
, i.uid AS i_uid
, i.user
, i.itemuid
, IF(i.user='alex',1,0) AS fav
FROM itemlist c
LEFT
JOIN fav i ON i.itemuid = c.uid
Note that the original query had two columns named uid; if you want to return both, and be able to reference both of those by column name, you need to have distinct names for each. In the query above, I've assigned an alias to the i.uid column so that both uid columns will be available by distinct column name.

Find the max value of a column, then group by another column in same table

I have a similar problem to the one solved here, but when I try the solution I think it fails because I have things set up differently..
I have a doc table with...
(unfortunately table cant be edited due to it being an old system)
+-------+--------+----------+--------+
| Docid | title | revision | linkid |
+-------+--------+----------+--------+
| 1 | docone | 1 | 1 |
| 2 | doctwo | 1 | 2 |
| 3 | docone | 2 | 1 |
|4 | docone | 3 | 1 |
+-------+--------+----------+--------+
On a page that lists all the documents I want to list only the latest revision of each document. Doc1 for example is on revision 3 so I want that one and not the other 2. Doc2 is only on revision 1 so show that one.
Based on the problem in the other post I have writen my query as follows......
$query_docs = "
SELECT `document`.*, doctype.*
FROM `document`
INNER JOIN doctype
ON `document`.iddoctypes = doctype.iddoctypes
WHERE `document`.revision = (
SELECT MAX(`document`.revision) AS revision
FROM `document`
)
GROUP BY `document`.linkid
ORDER BY `document`.doccreation DESC";
I have had to link to another table to get the document type (just to make the query harder).
Try this, I made a couple minor changes
SELECT document.*, doctype.*
FROM document
INNER JOIN doctype
ON document.iddoctypes = doctype.iddoctypes
WHERE document.revision = (
SELECT MAX(d1.revision)
FROM document d1
WHERE document.linkid = d1.linkid
)
ORDER BY document.doccreation DESC
Just a wild guess: I think you have to add group by title in your (select max(...) ...) subquery.
So the complete statement will be this:
$query_docs = "
SELECT `document`.*, doctype.*
FROM `document`
INNER JOIN doctype
ON `document`.iddoctypes = doctype.iddoctypes
WHERE `document`.revision = (
SELECT MAX(`document`.revision) AS revision
FROM `document`
--GROUP BY `document`.title
GROUP BY `document`.linkid
)
GROUP BY `document`.linkid
ORDER BY `document`.doccreation DESC";
Am I missing something? This seems completely straightforward...
SELECT x.*
FROM my_table x
JOIN (SELECT title,MAX(revision) max_revision FROM my_table GROUP BY title) y
ON y.title = x.title
AND y.max_revision = x.revision;

Select from two tables where rows from second table should be shown as columns in first

I have two tables in MySQL:
Table entry:
id | name | date
1 | Test Entry | 12/12/2013
2 | Test Entry 2 | 12/12/2013
Table note
id | entry_id | name | value
1 | 1 | note1 | value1
2 | 1 | note2 | value2
3 | 2 | note1 | value1
4 | 3 | note4 | value4
Where entry_id in note is a foreign key to id in entry.
Is there any solution I can create with a SELECT that will give me a result like the following?
entry_id | name | note1 | note2 | note3
1 | Test Entry | value1 | value2 | -
2 | Test Entry 2 | value 1 | - | value3
I want to avoid LEFT JOIN here (current implementation is working like this) and want to join note only once if that is possible. LEFT JOIN is not good here, because I do not know how many notes can be attached to one entry. My current implementation works that way that I first fetch all distinct notes by name that can be found in note, and then build a SELECT with foreach through PHP. Finally, the SELECT statement looks like this:
SELECT
E.id as entry_id,
E.name as name,
N1.value as note1_value,
N2.value as note2_value,
N3.value as note3_value
FROM entry E
JOIN LEFT note N1 ON E.id = N1.entry_id AND N1.name = 'note1'
JOIN LEFT note N2 ON E.id = N2.entry_id AND N2.name = 'note2'
JOIN LEFT note N3 ON E.id = N3.entry_id AND N3.name = 'note3'
Things get tricky when I join on note 20-30 times.
No, there is not a way to do that without joins.
I would recommend doing 2 queries.
select * from entry where id = id
select * from note where entry_id = id
and then join the results in your application code. You're right, the left joins are going to be bad.
Best would be to use a table with one note value and a note type (number) per each line.
id | value | note_no
Like this you can use as much notes as you like.
You can get the notes on one line using group_concat.
For an example, see here: http://lietoservetruth.wordpress.com/2010/12/13/mysql-group_concat-vertival-concat-concat-records/
This is faster than asking DB twice, and it's better DB design...

Categories