I'm having problems constructing a select query.
I have a table which I have shown in a simplified version below. There are many more columns than those I have shown, but I have ommitied those not relevent to this query.
ID ReceiptNo TransactionType
--------------------------------
1 | 2SJ1532 | SALE
2 | 8UG7825 | SALE
3 | 0619373 | SALE
4 | 8UG7825 | RFND
5 | | TEST
I want to select only those rows that have a transaction type "SALE" where the ReceiptNo for the selected row also appears in a row with transaction type RFND.
So in the above example I would want to select Row 2. Because it has Transaction Type SALE
and its ReceiptNo also appears in a row with transaction type RFND.
I have the following query to select all the SALE type transaction types, but I think I need a subquery to make the select work as descriped above. If anyone could help that would be great.
SELECT * FROM $table_name WHERE RecieptNo IS NOT NULL AND TRIM(RecieptNo) <> '' AND TransactionType = 'SALE'
Try this:
SELECT *
FROM $table_name
WHERE RecieptNo IN(SELECT RecieptNo
FROM tablename
WHERE TransactionType IN('Sale', 'RFND')
GROUP BY RecieptNo
HAVING COUNT( DISTINCT TransactionType) = 2);
This will ensure that the selected RecieptNo have both transaction types Sale, RFND.
SELECT t.*
FROM your_table t
JOIN your_table t2 ON t2.TransactionType = 'RFND' AND t2.ReceiptNo=t.ReceiptNo
GROUP BY t.ID
SELECT *
FROM $table_name X1
WHERE X1.TransactionType = 'SALE'
AND EXISTS (
SELECT X2.ReceiptNo
FROM $table_name X2
WHERE X1.ReceiptNo=X2.ReceiptNo
AND X2.TransactionType = 'RFND'
)
Related
I have the table:
id | date_submitted
1 | 01/01/2017
1 | 01/02/2017
2 | 01/03/2017
2 | 01/04/2017
I'm looking for the correct SQL to select each row, limited to one row per id that has the latest value in date_submitted.
So the SQL should return for the above table:
id | date_submitted
1 | 01/02/2017
2 | 01/04/2017
The query needs to select everything in the row, too.
Thanks for your help.
You can find max date for each id in subquery and join it with the original table to get all the rows with all the columns (assuming there are more columns apart from id and date_submitted) like this:
select t.*
from your_table t
inner join (
select id, max(date_submitted) date_submitted
from your_table
group by id
) t2 on t.id = t2.id
and t.date_submitted = t2.date_submitted;
Note that this query will return multiple rows for an id in case there are multiple rows with date_submitted equals to max date_submitted for that id. If you really want only one row per id, then the solution will be a bit different.
If you just need id and max date use:
select id, max(date_submitted) date_submitted
from your_table
group by id
i have a table like this
id(pk)|product_id(fk)|serial(varchar)|status(varchar)
1 | 2 | e098 | sold
2 | 2 | e008 | faulty
what i need to extract is:
array(faulty=>1,sold=>1)
i i can do it with a complex query, is there any SIMPLE query which can help?
i tried this:
SELECT COUNT(id) as product_details.status FROM product_details WHERE product_id=2 GROUP BY status which didn't work.
(ab)Use mysql's auto-typecasting:
SELECT SUM(status='sold') AS sold, SUM(status='faulty') AS faulty
FROM ...
the boolean result of status='sold' will be typecast to integer 0/1 and then summed up.
The other option is just to do a regular query and then do the pivoting in client-side code:
SELECT id, status, COUNT(status) AS count
FROM ...
GROUP BY id, status
and then
while(... fetch ...) {
$results[$row['id']][$row['status']] = $row['count'];
}
You want to query status as well like this.
SELECT status, COUNT(id) as count FROM product_details WHERE product_id=2 GROUP BY status
I'm trying to sort the resutls of a SELECT statement using a custom order like so:
SELECT * FROM table ORDER BY FIELD(id,4,5,6) LIMIT 6
I was expecting to have returned rows with ids: 4,5,6,1,2,3 but instead I'm getting 1,2,3,7,8,9. What am I doing wrong?
As a side note: Prior to running this query, I'm pulling this sort order from the database using a different SELECT with a GROUP_CONCAT function like so:
SELECT group_concat(clickID ORDER BY count DESC separator ',') from table2 WHERE searchphrase='$searchphrase'
This results in the 4,5,6 which is then used in the main query. Is there a faster way to write this all in one statement?
Try it this way
SELECT *
FROM table1
ORDER BY FIELD(id, 4,5,6) > 0 DESC, id
LIMIT 6
Output:
| ID |
|----|
| 4 |
| 5 |
| 6 |
| 1 |
| 2 |
| 3 |
Here is SQLFiddle demo
There is no need of the FIELD function. That will only make things slow.
You just need to properly use the ORDER BY:
SELECT * FROM table
ORDER BY id IN (4,5,6) DESC, id
LIMIT 6
here's how to do it all in one query
SELECT DISTINCT t1.*
FROM table t1
LEFT JOIN table2 ON t1.id = t2.clickID AND t2.searchphrase='$searchphrase'
ORDER BY t2.clickID IS NULL ASC, t1.id ASC
When the LEFT JOIN finds no match, it sets the fields in t2 to NULL in the returned row. This orders by this nullness.
I need to update cells within a specific column based upon ids in another column. The column names are Prod_ID, Lang_ID and Descr:
Prod_ID | Lang_ID | Descr
--------+---------+------
A101 | 1 | TextA
A101 | 2 | TextB
A101 | 3 | TextC
For a group of rows with the same Prod_ID, I need to replace all subsequent descriptions (Descr column) with the description of the first row. The row with the correct description has always Lang_ID = 1. Also, the table may not be sorted by Lang_ID.
Example: TextA (Lang_ID = 1) should replace TextB and TextC because the Prod_IDs of the rows match.
You mentioned in a comment elsewhere that the "master" lang_id is always 1. That simplifies things greatly, and you can do this with a simple self-join (no subqueries :-)
This query selects all lang_1 rows, then joins them with all non-lang_1 rows of the same prod_id and updates those.
If Lang_ID=1 is always the "first"
UPDATE products
LEFT JOIN products as duplicates
ON products.Prod_ID=duplicates.Prod_ID
AND duplicates.Lang_ID != 1
SET duplicates.Descr = products.Descr
WHERE products.Lang_ID = 1
edit: If Lang_ID=1 may not be the "first"
you can join the table to itself via a an intermediate join which finds the lowest Lang_ID for that row. I have called the intermediate-join "lang_finder".
UPDATE products
LEFT JOIN (SELECT Prod_ID, MIN(Lang_ID) as Lang_ID FROM products GROUP BY Prod_ID) as lang_finder
ON products.prod_id=lang_finder.prod_id
LEFT JOIN products as cannonical_lang
ON products.Prod_ID = cannonical_lang.Prod_ID
AND lang_finder.Lang_ID = cannonical_lang.Lang_ID
SET products.Descr = cannonical_lang.Descr
Note that while it does use a subquery, it does not nest them. The subquery essentially just adds a column to the products table (virtually) with the value of the lowest Lang_ID, which then allows a self-join to match on that. So if there were a product with Lang_ID 3, 4, & 5, this would set the Descr on all of them to whatever was set for Lang_ID 3.
How about this?
UPDATE myTable dt1, myTable dt2
SET dt1.Descr = dt2.Descr
WHERE dt1.Prod_ID=dt2.Prod_ID;
Demo at sqlfiddle
Assuming that the correct description is always in the row of a group of rows with the same Prod_ID where Lang_ID has the smallest value, this MySQL query should work:
UPDATE your_table AS t1
JOIN (
SELECT Prod_ID, Descr
FROM (
SELECT *
FROM your_table
ORDER BY Lang_ID
) AS t3
GROUP BY Prod_ID
) AS t2
ON t1.Prod_ID = t2.Prod_ID
SET t1.Descr = t2.Descr;
The above can be used e.g. if Lang_ID is a primary or unique key. It also works if the corresponding Lang_ID has always the same minimum value (e.g. = 1) but in that case much less complex queries like this one are possible.
i need to get the latest order (from our custon admin panel). here's my query:
select *
from order
left join customer
on (customer.id = order.fk_cid)
where date = curdate()
order by time desc
limit 1;
this output everything from orders and customers which i need except 1 therefore that is why i use the *
here's my table structure:
order table:
id, fk_cid, date, time
customer table:
id, name, lastname, street, city, zip, country, phone, email, lastlogin
now, in my php i have:
$result = mysql_query("
select *
from `order`
left join customer
on (customer.id = order.fk_cid)
where date = curdate()
order by time desc
limit 1");
$row = mysql_fetch_assoc($result, MYSQL_ASSOC);
at this point my order is not correct, why?
Your customers.id is overwriting the order.id because you are using the same column name.
select *
from `order`
left join customer on (customer.id = order.fk_cid)
where date = curdate() order by time desc limit 1;
+------+--------+------------+----------+------+-------+------
| id | fk_cid | date | time | id | name | ....
+------+--------+------------+----------+------+-------+------
| 1 | 2 | 2011-11-30 | 07:01:23 | 2 | asasd | ....
+------+--------+------------+----------+------+-------+------
1 row in set (0.03 sec)
As you can see in this example you have two id, so PHP when retrieve the data using mysql_fetch_assoc it overwrites the second id because it's the same key in the array. To fix this, you will have to specify the columns in your query:
select `order`.id AS order_id, customer.id AS customer_id, customer.name /* etc... */
This will output:
Also, I recommend to use different name for your tables and fields. order, date, time since they are reserved word (in case you forget for use the ` ).
Array
(
[order_id] => 1
[customer_id] => 2
// etc...
)
Also here's a topic you should read: Why is SELECT * considered harmful?