I am using a MySQL query to fetch data from 2 tables. Here I have a status Transfer Out in table2. I do need to fetch all the details with status Transfer Out and at the same time, there should not be any details with Transfer In status which is added after the Transfer Out. So that I should not get the details which are Transfer back In after a Transfer Out.
Right now I am using subquery for the same. But when the data count gets higher, it is causing timeout issues. Is there a better way to rewrite the query and get the same result?
My query sample is
SELECT sq.etid
FROM (
SELECT og.etid, pt.timestamp
FROM og_membership og
INNER JOIN table1 n ON(n.nid=og.etid)
INNER JOIN table2 pt ON(og.etid=pt.animal_nid)
WHERE og.entity_type='node'
AND pt.partner_gid = :gid
AND pt.shelter_gid = :our_gid
AND pt.type = 'Transfer Out'
AND (
SELECT count(id)
FROM table2
WHERE timestamp > pt.timestamp
AND type = 'Transfer In'
AND partner_gid = :gid
AND shelter_gid = :our_gid
) = 0
) AS sq
You could possibly do this with a group by for example
select something
from somehwere
group by something having isnull(max(out_date),0) > isnull(max(indate) ,0)
For example
DROP TABLE IF EXISTS LOANS;
CREATE TABLE LOANS (ID INT AUTO_INCREMENT PRIMARY KEY, ISBN INT,DIRECTION VARCHAR(3), DT DATETIME);
INSERT INTO LOANS(ISBN,DIRECTION,DT) VALUES
(1,'OUT','2017-10-01 09:00:00'),
(2,'OUT','2017-10-02 10:00:00'),
(2,'IN', '2017-10-02 10:10:00'),
(3,'REC','2017-10-02 10:00:00'),
(4,'REC','2017-10-02 10:00:00'),
(4,'OUT','2017-10-03 10:00:00'),
(4,'IN', '2017-10-04 10:00:00'),
(4,'OUT','2017-10-05 10:00:00')
;
SELECT ISBN
FROM LOANS
WHERE DIRECTION IN('OUT','IN')
GROUP BY ISBN HAVING
MAX(CASE WHEN DIRECTION = 'OUT' THEN DT ELSE 0 END) >
MAX(CASE WHEN DIRECTION = 'IN' THEN DT ELSE 0 END) ;
result
+------+
| ISBN |
+------+
| 1 |
| 4 |
+------+
2 rows in set (0.00 sec)
In case of a tie on DT you could substitute id.
Change
( SELECT COUNT(id) FROM ... ) = 0
to
EXISTS ( SELECT 1 FROM ... )
Get rid of the outermost query and the first pt.timestamp. (Or is there some obscure reason for pt.timestamp?)
table2 needs INDEX(type, partner_gid, shelter_gid, timestamp). timestamp must be last, but the others can be in any order.
table2 needs INDEX(type, partner_gid, shelter_gid, animal_nid); the columns can be in any order. (This index cannot be combined with the previous one.)
og_membership needs INDEX(etid, entity_type) (in either order).
Why do you have INNER JOIN table1 n ON(n.nid=og.etid) in the query? table1 does not seem to be used at all -- except maybe for verifying the existence of a row. Remove it if possible.
After making changes, please provide EXPLAIN SELECT ... and SHOW CREATE TABLE for the 2 (or 3??) tables.
I want to add Total_Price from Food_Order table and Drinks_Order table into Order table. However, it gave me Error: #1242 - Subquery returns more than 1 row.
The coding to add values from 2 tables:
UPDATE `ORDER`
SET Total_Price =
(SELECT Total_Price FROM FOOD_ORDER WHERE FOOD_ORDER.Order_ID
=`ORDER`.Order_ID) + (SELECT Total_Price FROM DRINKS_ORDER WHERE
DRINKS_ORDER.Order_ID = `ORDER`.Order_ID);
Coding for FOOD_ORDER,DRINKS_ORDER and ORDER table :
INSERT INTO `ORDER` (`Order_ID`, `Pay_Method`, `Pay_status`, `Order_Time`, `Cus_ID`, `Emp_ID`)VALUES
('1000000001','CASH','PAID','2015-09-05 12:58:51','100000','10000006'),
('1000000002','CASH','PAID','2015-09-05 14:45:00','100001','10000009'),
('1000000003','CREDIT CARD','PAID','2015-09-05 16:34:21','100002','10000002'),
('1000000004','CASH','PAID','2015-09-05 17:10:10','100003','10000009'),
('1000000005','CREDIT CARD','PAID','2015-09-06 12:33:11','100004','10000007'),
('1000000006','CREDIT CARD','PAID','2015-09-06 15:51:15','100005','10000004'),
('1000000007','CASH','PAID','2015-09-06 16:20:05','100006','10000003'),
('1000000008','','UNPAID','2015-09-06 17:00:00','100007','10000006'),
('1000000009','','UNPAID','2015-09-06 17:23:15','100008','10000002'),
('1000000010','','UNPAID','2015-09-06 17:30:34','100009','10000007')
INSERT INTO `FOOD_ORDER` VALUES
('F000001','3','39.90','1000000001','201'),
('F000002','1','22.50','1000000002','108'),
('F000003','2','25.40','1000000003','203'),
('F000004','2','25.20','1000000004','101'),
('F000005','2','26.60','1000000005','202'),
('F000006','1','30.40','1000000006','103'),
('F000007','1','30.40','1000000007','106'),
('F000008','2','7.60','1000000008','803'),
('F000009','2','26.60','1000000009','202'),
('F000010','4','16.00','1000000010','801')
INSERT INTO `DRINKS_ORDER` VALUES
('D000001','2','16.00','1000000001','907'),
('D000002','1','4.00','1000000001','903'),
('D000003','1','3.00','1000000003','905'),
('D000004','2','16.00','1000000005','908'),
('D000005','2','6.00','1000000006','901'),
('D000006','2','6.00','1000000006','902'),
('D000007','1','3.00','1000000008','905'),
('D000008','2','6.00','1000000009','906'),
('D000009','1','3.00','1000000010','904')
The Order_ID in FOOD_ORDER and in DRINKS_ORDER is not unique. If you want to add all prices, use SUM:
UPDATE `ORDER`
SET Total_Price = (SELECT SUM (Total_Price) FROM FOOD_ORDER
WHERE FOOD_ORDER.Order_ID =`ORDER`.Order_ID) +
(SELECT SUM (Total_Price) FROM DRINKS_ORDER
WHERE DRINKS_ORDER.Order_ID = `ORDER`.Order_ID);
I am trying to create a column that contains counts, but the problem is where I go to reuse the subquery that does this the temporary table created previously becomes unavailable as it no longer exists.
My question is how can I store the result of a previous subquery so I can run something on that result later on in the same query?
First for the counts I have:
CREATE TEMPORARY TABLE _temp_unique_entity_manufacturers
(
entityId INT(11),
manufacturerRef INT(11),
manufacturerName VARCHAR(255),
KEY(entityId),
KEY(manufacturerRef)
)
ENGINE=MEMORY AS
(SELECT DISTINCT entityRef AS entityId, manufacturer AS manufacturerRef, pm.name AS manufacturerName FROM enquiries, parts_trading, parts_manufacturers AS pm WHERE manufacturer = pm.id AND enquiryRef = enquiries.id)
And then in my main query I work with this table, specifically this part:
IF((SELECT COUNT(*) FROM _temp_unique_entity_manufacturers WHERE entityId = eo.id) > 0,
(SELECT COUNT(*) FROM _temp_unique_entity_manufacturers WHERE entityId = eo.id),
0
) AS manufacturers
The second subquery fails because the temp table is gone at this point. Is there a way where I dont have to write out the same subquery again and again?
case when
((SELECT COUNT(*) FROM _temp_unique_entity_manufacturers WHERE entityId = eo.id) > 0) then
(SELECT COUNT(*) FROM _temp_unique_entity_manufacturers WHERE entityId = eo.id) else
0 end
) AS manufacturers
--------------
ex:
select coname,(case when cond then result else second result end) as user_colname from
tablename
----------------------
If condition implement in sql as case when statement
I have a table with 3 columns: id, date and name. What I am looking for is to delete the records that have a duplicate name. The rule should be to keep the record that has the oldest date. For instance in the example below, there is 3 records with the name Paul. So I would like to keep the one that has the oldest date (id=1) and remove all the others (id = 4 and 6). I know how to make insert, update, etc queries, but here I do not see how to make the trick work.
id, date, name
1, 2012-03-10, Paul
2, 2012-03-10, James
4, 2012-03-12, Paul
5, 2012-03-11, Ricardo
6, 2012-03-13, Paul
mysql_query(?);
The best suggestion I can give you is create a unique index on name and avoid all the trouble.
Follow the steps as Peter Kiss said from 2 to 3. Then do this
ALTER Table tablename ADD UNIQUE INDEX name (name)
Then Follow 4 Insert everything from the temporary table to the original.
All the new duplicate rows, will be omitted
Select all the records what you want to keep
Insert them to a temporary table
Delete everything from the original table
Insert everything from the temporary table to the original
Like Matt, but without the join:
DELETE FROM `table` WHERE `id` NOT IN (
SELECT `id` FROM (
SELECT `id` FROM `table` GROUP BY `name` ORDER BY `date`
) as A
)
Without the first SELECT you will get "You can't specify target table 'table' for update in FROM clause"
Something like this would work:
DELETE FROM tablename WHERE id NOT IN (
SELECT tablename.id FROM (
SELECT MIN(date) as dateCol, name FROM tablename GROUP BY name /*select the minimum date and name, for each name*/
) as MyInnerQuery
INNER JOIN tablename on MyInnerQuery.dateCol = tablename.date
and MyInnerQuery.name = tablename.name /*select the id joined on the minimum date and the name*/
) /*Delete everything which isn't in the list of ids which are the minimum date fore each name*/
DELETE t
FROM tableX AS t
LEFT JOIN
( SELECT name
, MIN(date) AS first_date
FROM tableX
GROUP BY name
) AS grp
ON grp.name = t.name
AND grp.first_date = t.date
WHERE
grp.name IS NULL
DELETE FROM thetable tt
WHERE EXISTS (
SELECT *
FROM thetable tx
WHERE tx.thename = tt.thename
AND tx.thedate > tt. thedate
);
(note that "date" is a reserver word (type) in SQL, "and" name is a reserved word in some SQL implementations)