Hello I have an issue I am working on for a theoretical problem. Assume I have these two tables
Order Table
Entry
Order#
DatePlaced
Type
2001
5
2021-05-03
C
Status Table
Entry
Order#
Status
Date
Deleted
2001
5
S
2021-05-04
0
2002
5
D
2021-05-05
0
So I need to be able to get this
Expected Table
Entry
Order#
DatePlaced
Type
Status
Date
Deleted
2002
5
2021-05-03
C
D
2021-05-05
0
This would be fairly easy if I could just left join the data. The is issue is that the sql in the code is already written like this. The tables are joined based on the entry. Every time a new status occurs for an order# the entry in the Order Table is updated EXCEPT when it is delivered. Do to how dependent the code is I cannot simply update the initial query below. I was wondering if there is a join or way without using SET that I can get the last status based on the order? I was thinking we can check the order and then the entry but I am not sure how to join that with the Current Table (data we get from query)
SELECT * FROM orders or
LEFT JOIN status st ON or.entry = st.entry
WHERE st.deleted = 0;
This results in this
Current Table
Entry
Order#
DatePlaced
Type
Status
Date
Deleted
2001
5
2021-05-03
C
S
2021-05-04
0
Is there a way to JOIN the status table with the Current Table so that the status columns become what I expect?
This will work just fine:
SELECT s.entry, s.order_no, o.date_placed, o.type, s.status, s.date, s.deleted
FROM `orders` o
INNER JOIN `status` s ON (
s.order_no=o.order_no AND s.entry=(SELECT MAX(entry) FROM status WHERE order_no = o.order_no)
)
Live Demo
https://www.db-fiddle.com/f/twz1TT9VH7YNTY1KrpRAjx/3
Does the last status have a higher entry number or higher date created?
Perhaps include MAX(st.Entry) as last_entry in your SELECT clause,
Maybe select your fields explicitly
vs SELECT *
and include a
GROUP BY
after your WHERE clause
and a
HAVING
after your GROUP BY
create table orders (
entry INT,
order_number INT,
date_placed date,
order_type VARCHAR(1) )
create table order_status (
entry INT,
order_number INT,
order_status VARCHAR(1),
date_created date,
deleted INT
);
INSERT INTO orders (entry, order_number, date_placed, order_type) VALUES (2001, 5, '2021-05-03', 'C');
INSERT INTO order_status (entry, order_number, order_status, date_created, deleted)
VALUES
(2001, 5, 'S', '2001-05-04', 0),
(2002, 5, 'D', '2001-05-05', 0);
SELECT os.entry, o.order_number, o.date_placed, o.order_type,
os.order_status, os.date_created, os.deleted,
MAX(os.entry) as last_entry
FROM orders o
LEFT JOIN order_status os
ON o.order_number = os.order_number
GROUP BY o.order_number
HAVING os.entry = last_entry
Related
I have two tables:
TABLE A
Unique_id
id
price
1
1
10.50
2
3
14.70
3
1
12.44
TABLE B
Unique_id
Date
Category
Store
Cost
1
2022/03/12
Shoes
A
13.24
2
2022/04/15
Hats
A
15.24
3
2021/11/03
Shoes
B
22.31
4
2000/12/14
Shoes
A
15.33
I need to filter TABLE A on a known id to get the Unique_id and average price to join to Table B.
Using this information I need to know which stores this item was sold in.
I then need to create a results table displaying the stores and the amount of days sales were recorded in the stores - regardless of whether the sales are associated with the id and the average cost.
To put it more simply I can break down the task into 2 separate commands:
SELECT AVG(price)
FROM table_a
WHERE id = 1
GROUP BY unique_id;
SELECT store, COUNT(date), AVG(cost)
FROM table_b
WHERE category = 'Shoes'
GROUP BY store;
The unique_id should inform the join but when I join the tables it messes up my COUNT function and only counts the days in which the id is connected - not the total store sales days.
The results should look something like this:
Store
AVG price
COUNT days
AVG cost
A
10.50.
3
14.60.
B
12.44
1.
22.31.
I wwas hard to grasp, what you wanted, but after some thinking and your clarification, it can be solved as the code shows
CREATE TABLE TableA
(`Unique_id` int, `id` int, `price` DECIMAL(10,2))
;
INSERT INTO TableA
(`Unique_id`, `id`, `price`)
VALUES
(1, 1, 10.50),
(2, 3, 14.70),
(3, 1, 12.44)
;
CREATE TABLE TableB
(`Unique_id` int, `Date` datetime, `Category` varchar(5), `Store` varchar(1), `Cost` DECIMAL(10,2))
;
INSERT INTO TableB
(`Unique_id`, `Date`, `Category`, `Store`, `Cost`)
VALUES
(1, '2022-03-12 01:00:00', 'Shoes', 'A', 13.24),
(2, '2022-04-15 02:00:00', 'Hats', 'A', 15.24),
(3, '2021-11-03 01:00:00', 'Shoes', 'B', 22.31),
(4, '2000-12-14 01:00:00', 'Shoes', 'A', 15.33)
SELECT
B.`Store`
, AVG(A.`price`) price
, (SELECT COUNT(*) FROM TableB WHERE `Store` = B.`Store` ) count_
, (SELECT AVG(
`cost`) FROM TableB WHERE `Store` = B.`Store` ) price
FROM TableA A
JOIN TableB B ON A.`Unique_id` = B.`Unique_id`
WHERE B.`Category` = 'Shoes'
GROUP BY B.`Store`
Store | price | count_ | price
:---- | --------: | -----: | --------:
A | 10.500000 | 3 | 14.603333
B | 12.440000 | 1 | 22.310000
db<>fiddle here
This should be the query you are after. Mainly you simply join the rows using an outer join, because not every table_b row has a match in table_a.
Then, the only hindrance is that you only want to consider shoes in your average price. For this to happen you use conditional aggregation (a CASE expression inside the aggregation function).
select
b.store,
avg(case when b.category = 'Shoes' then a.price end) as avg_shoe_price,
count(b.unique_id) as count_b_rows,
avg(b.cost) as avg_cost
from table_b b
left outer join table_a a on a.unique_id = b.unique_id
group by b.store
order by b.store;
I must admit, it took me ages to understand what you want and where these numbers result from. The main reason for this is that you have WHERE table_a.id = 1 in your query, but this must not be applied to get the result you are showing. Next time please look to it that your description, queries and sample data match.
(And then, I think that names like table_a, table_b and unique_id don't help understanding this. If table_a were called prices instead and table_b costs and unique_id were called cost_id then, I wouldn't have had to wonder how the tables are related (by id? by unique id?) and wouldn't have had to look again and again which table the cost resides in, which table has a price and which table is the outer joined one while looking at the problem, the requested result and while writing my query.)
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.
Ledgers Table
ledger_id ledger_name dep_id dr_bal cr_bal
1 Purchase 2 NUll NUll
Transaction Table
trans_id trans_date ledger_id ledger_name amount trans_type
1 3/2/2004 1 Purchase A/C 84500 dr
2 3/12/2004 6 Cash A/C 20000 cr
These are my tables, Ledgers and Transactions.
I want to update ledgers.dr_bal from transactions.amount,
based on ledger_id which is the primary key in ledgers table.
Want to copy the values from transactions.amount to dr_bal based on trans_type ='dr'
So far I have tried doing ,
UPDATE ledgers
SET dr_bal =(select sum(If(tbl_transactions.trans_type = 'dr' AND transactions.ledger_id = 1), amount,0) FROM transactions)
where ledgers.ledger_id =1;
But am unable to run the above query, as it throws an error at the Where clause at the end.
Have tried looking into various questions related to updating tables here. But am really stuck.
Try this query!
UPDATE ledgers
LEFT JOIN
(SELECT
SUM(amount) soa, ledger_id
FROM
tbl_transactions
WHERE
tbl_transactions.trans_type = 'dr'
AND tbl_transactions.ledger_id = 1) t ON (ledgers.ledger_id = t.ledger_id)
SET
ledgers.dr_bal = coalesce(t.soa, 0);
If you would like to update all ledgers with the transactions amount, remove the condition of tbl_transactions.ledger_id = 1 and introduce GROUP BY tbl_transactions.ledger_id in the sub-query.
I have a MySql table named 'comments' :
id | date | movie_id | comment_value
1 2011/11/05 10 comment_value_1
2 2012/01/10 10 comment_value_2
3 2011/10/10 15 comment_value_3
4 2011/11/20 15 comment_value_4
5 2011/12/10 30 comment_value_5
And i try to have the most recent comment for each movie with the query :
SELECT MAX(date),id,date,movie_id,comment_value FROM comments GROUP BY movie_id
The MAX(date) return the most recent date, but the row associated (movie_id,id,comment_value,date) did not match. It returns the value of the first comment of the movie, like this :
MAX(date) | id | date | movie_id | comment_value
2012/01/10 1 2011/11/05 10 comment_value_1
2011/11/20 3 2011/10/10 15 comment_value_3
2011/12/10 5 2011/12/10 30 comment_value_5
So, my question is : how can i have the most recent comment for each movie, in only one query ( i'm actually using a second query to get the good comment)
Using two queries isn't so bad. Otherwise you can do something like
SELECT id, date, movie_id, comment_value FROM comments c JOIN
(SELECT movie_id, MAX(date) date FROM comments GROUP BY movie_id) x
ON x.movie_id=c.movie_id AND x.date=c.date GROUP BY movie_id;
Try this:
SELECT c1.*
FROM comments c1
LEFT JOIN comments c2 ON (c1.movie_id = c2.movie_id AND c1.date < c2.date)
WHERE c2.id IS NULL
Because of the join condition it will be able to join only the rows which don't contain the maximum date value, so filtering the rows with c2.id IS NULL gives you rows with maximum values.
create table comments (id int,movie_dt datetime,movie_id int,comment_value nvarchar(100))
insert into comments values (1,'2011/11/05',10,'comment_value_1')
insert into comments values (2,'2012/01/10',10,'comment_value_2')
insert into comments values (3,'2011/10/10',15,'comment_value_3')
insert into comments values (4,'2011/11/20',15,'comment_value_4')
insert into comments values (5,'2011/12/10',30,'comment_value_5')
select a.id, m.movie_dt, m.movie_id,a.comment_value
from comments a
inner join
(
SELECT MAX(movie_dt) movie_dt,movie_id
FROM comments
GROUP BY movie_id
) m on (a.movie_dt = m.movie_dt and a.movie_id = m.movie_id)
Is it possible to use a DATETIME field instead of just DATE? That would make the query a lot easier plus give better reporting capabilities. You can always aggregate the DATETIME field down to something more specific if needed.
Having trouble with a query to return the newest order of any grouped set of orders having more than 1 order. CREATE & INSERTs for the test data are below.
This query returns the unique customer id's I want to work with, along with the grouped order_id's. Of these records, I only need the most recent order (based on date_added).
SELECT COUNT(customer_id), customer_id, GROUP_CONCAT(order_id) FROM orderTable GROUP BY customer_id HAVING COUNT(customer_id)>1 LIMIT 10;
mysql> SELECT COUNT(customer_id), customer_id, GROUP_CONCAT(order_id) FROM orderTable GROUP BY customer_id HAVING COUNT(customer_id)>1 LIMIT 10;
+--------------------+-------------+------------------------+
| COUNT(customer_id) | customer_id | GROUP_CONCAT(order_id) |
+--------------------+-------------+------------------------+
| 2 | 0487 | F9,Z33 |
| 3 | 1234 | 3A,5A,88B |
+--------------------+-------------+------------------------+
2 rows in set (0.00 sec)
I'm looking for order Z33 (customer_id 0487) and 3A (customer_id 1234).
For clarification, I do not want orders for customers that have only ordered once.
Any help or tips to get me pointed in the right direction appreciated.
Sample table data:
--
-- Table structure for table orderTable
CREATE TABLE IF NOT EXISTS orderTable (
customer_id varchar(10) NOT NULL,
order_id varchar(4) NOT NULL,
date_added date NOT NULL,
PRIMARY KEY (customer_id,order_id)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
--
-- Dumping data for table orderTable
INSERT INTO orderTable (customer_id, order_id, date_added) VALUES
('1234', '5A', '1997-01-22'),
('1234', '88B', '1992-05-09'),
('0487', 'F9', '2002-01-23'),
('5799', 'A12F', '2007-01-23'),
('1234', '3A', '2009-01-22'),
('3333', '7FHS', '2009-01-22'),
('0487', 'Z33', '2004-06-23');
==========================================================
Clarification of the query.
The question was to only include those customers that had more... hence my query has it INSIDE with the GROUP BY... This way it ONLY GIVES the customer in question that HAD multiple orders, but at the same time, only gives the most recent date OF the last order for the person... Then the PreQuery is re-joined to the orders table by the common customer ID, but only for the order that matches the last date as detected in the prequery. If a customer only had a single order, its inner PreQuery count would have only been 1 and thus excluded from the final PreQuery result set.
select ot.*
from
( select
customer_id,
max( date_added ) as LastOrderDate,
from
orderTable
having
count(*) > 1
group by
customer_id ) PreQuery
join orderTable ot
on PreQuery.Customer_ID = ot.Customer_ID
and PreQuery.LastOrderDate = ot.date_added