Multiple rows come back of same ID, just need one - mysql

I am trying to list several products on a page. My query returns multiples of the same product and I am trying to figure out how to limit it to one only with my query.
The primary key on the first table that we will call table_one is ID.
The second table has a column of ProductID that references the primary key on table_one.
My query brings me back multiples of my ProductID that is equal to 6 below. I just want one result to be brought back, BUT I still want my all of my data in DateReserved on table_two to be queried. Pretty sure I need to add one more thing to my query, but I have not had much luck.
The results I want back are as follows.
ID Productname Quantity Image Date Reserved SumQuantity
6 productOne 6 'image.jpg' 03-31-2013 3
7 productTwo 1 'product.jpg' 04-04-2013 1
Here is my first table. table_one
ID Productname Quantity Image
6 productOne 6 'image.jpg'
7 productTwo 1 'product.jpg'
Here is my second table. table_two
ID ProductID DateReserved QuantityReserved
1 6 03-31-2013 3
2 6 04-07-2013 2
3 7 04-04-2013 1
Here is my query that I am trying to use.
SELECT *
FROM `table_one`
LEFT JOIN `table_two`
ON `table_one`.`ID` = `table_two`.`ProductID`
WHERE `table_one`.`Quantity` > 0
OR `table_two`.`DateReserved` + INTERVAL 5 DAY <= '2013-03-27'
ORDER BY ProductName

Sorry for posting another answer, but as it seems my first try on it was not so good ;)
To only get one result row per reservation you need to sum them up somehow.
First I suggest you explicitly select the columns you want back in your result and don't use "*".
I suggest you try something like this:
SELECT
`table_one`.`ID`, `table_one`.`Productname`, `table_one`.`Image`, `table_one`.`Quantity`,
`table_two`.`ProductID`, SUM(`table_two`.`QuantityReserved`)
FROM
`table_one`
LEFT JOIN
`table_two` ON `table_one`.`ID` = `table_two`.`ProductID`
WHERE
`table_one`.`Quantity` > 0
OR `table_two`.`DateReserved` + INTERVAL 5 DAY <= '2013-03-27'
GROUP BY `table_two`.`ProductID`
ORDER BY ProductName
As you see I used "SUM" to get a combined quantity, this is called aggregation and the "GROUP BY" helps you getting rid of multiple occurences of the same ProductID.
One problem that you have now is that you will have to get the reservation date from a seperate query (well at least I am now unsure how you would get it into the same query)

Since you are using MySQL
LIMIT <NUMBER>
should exactly do what you want, you just insert it after your ORDER BY clause, but probably you should also add one more ordering to that, so you can be sure that you will always get the one entity that you wanted and not just some "random" entity ;)
So without further ordering your query would look like this:
SELECT
*
FROM `table_one`
LEFT JOIN `table_two` ON `table_one`.`ID` = `table_two`.`ProductID`
WHERE
`table_one`.`Quantity` > 0
OR `table_two`.`DateReserved` + INTERVAL 5 DAY <= '2013-03-27'
ORDER BY ProductName
LIMIT 1
here some more description about that

SELECT a.member_id,a.member_name,a.gender,a.amount,b.trip_id,b.location
FROM tbl_member a
LEFT JOIN (SELECT trip_id, MAX(amount) as amount FROM tbl_member GROUP BY trip_id ) b ON a.trip_id= b.trip_id
LEFT JOIN tbl_trip b ON a.trip_id=c.trip_id
ORDER BY member_name

Related

Possible to count number of occurrences in a "group" in MySQL?

Sorry if the title is misleading, I don't really know the terminology for what I want to accomplish. But let's consider this table:
CREATE TABLE entries (
id INT NOT NULL,
number INT NOT NULL
);
Let's say it contains four numbers associated with each id, like this:
id number
1 0
1 9
1 17
1 11
2 5
2 8
2 9
2 0
.
.
.
Is it possible, with a SQL-query only, to count the numbers of matches for any two given numbers (tuples) associated with a id?
Let's say I want to count the number of occurrences of number 0 and 9 that is associated with a unique id. In the sample data above 0 and 9 does occur two times (one time where id=1 and one time where id=2). I can't think of how to write a SQL-query that solves this. Is it possible? Maybe my table structure is wrong, but that's how my data is organized right now.
I have tried sub-queries, unions, joins and everything else, but haven't found a way yet.
You can use GROUP BY and HAVING clauses:
SELECT COUNT(s.id)
FROM(
SELECT t.id
FROM YourTable t
WHERE t.number in(0,9)
GROUP BY t.id
HAVING COUNT(distinct t.number) = 2) s
Or with EXISTS():
SELECT COUNT(distinct t.id)
FROM YourTable t
WHERE EXISTS(SELECT 1 FROM YourTable s
WHERE t.id = s.id and s.id IN(0,9)
HAVING COUNT(distinct s.number) = 2)

Select redundant rows only, not the original

So I'm tasked with cleaning up a system that has generated redundant orders.
Data example of the problem
ORDER ID, SERIAL, ...
1 1
2 1
3 2
4 2
5 3
6 3
7 3
The above data shows that 2 orders were generated with serial 1, 2 orders with serial 2, and 3 orders with serial 3. This is not allowed, and there should be only one order per serial.
So I need a query that can identify the REDUNDANT orders ONLY. I'd like the query to exclude the original order.
So the output from the above data should be:
REDUNDANT ORDER IDS
2
4
6
7
I can easily identify which orders have duplicates using GROUP BY and HAVING COUNT(*) > 1 but the tricky part comes with removing the original.
Is it even possible?
Any help is greatly appreciated.
As posted in the comments, here's one way to achieve this:
SELECT T1.ORDER_ID as redundant
FROM thetable T1
LEFT JOIN
(
SELECT SERIAL, MIN(ORDER_ID) AS firstorder
FROM thetable
GROUP BY SERIAL
HAVING COUNT(*) > 1
) T2 ON T1.ORDER_ID=T2.firstorder
WHERE T2.firstorder IS NULL
SQL Fiddle

SQL query for selecting maximum from 2 different columns

I got a question in my homework for SQL about selecting the maximum values from the same table that have different class "Letters"
For example:
ID Student Group Avg(value)
-------------------------------------
1 stud1 A 9
2 stud2 A 9.5
3 stud3 B 8
4 stud4 B 8.5
What my query should do, is to show stud2 and stud4.The maximum from their respective groups.
I managed to do it in the end, but it took a lot of characters so I thought that maybe there's a shorter way to do. Any ideas? I used to first search the id or the stud that has max avg(value) from group A, intersecting with the id of the stud that has max avg(value) from B and then putting everything into one big select and then using those intersected IDs into another query that requested to show some different things about those IDs. But as I said, it looked far too long and thought that maybe there's an shorter way.
Try this (I renamed group to grp and avg to avg_val as those are reserved keywords):
select t1.*
from your_table t1
inner join (
select grp, max(avg_val) avg_val
from your_table
group by grp
) t2 on t1.grp = t2.grp
and t1.avg_val = t2.avg_val;
It finds maximum avg value per group and joins it with original table to get the corresponding students.
Please note that if there are multiple students with same avg as the max value of the that group, all of those students will be returned.

Find average between two date columns for specific rows in a group

I have a table with 2 dates in it and a product, and I need to get the average days difference between them considering just the last 3 rows for each product.
SELECT AVG(DATEDIFF(date2, date1)) FROM table WHERE product = 121
This gives me the average of all the date differences for product 121
SELECT AVG(DATEDIFF(date2, date1)) FROM table WHERE product = 121 LIMIT 3
Still gives me the average off all the records, ignoring the LIMIT argument.
Also when I try a different approach, it also does ignore the last argument and shows the average off all the rows.
SELECT AVG(DATEDIFF(date2, date1)) FROM table WHERE product =121 && date1 > 2015-01-01
Any idea on how to fix this or what I'm doing wrong?
When you have problems like this, I recommend breaking it up and putting it back.
Before doing any calculations, you know that you need the last three rows for each product. So, if you want for example the rows with the latest date2 you can select them by doing the following:
SELECT *
FROM myTable
WHERE product = 121
ORDER BY date2 DESC
LIMIT 3;
That will select the 3 latest rows you want. Then, just use that as a subquery to preform the aggregation. This way, the calculations are only made on the rows you are concerned with:
SELECT product, AVG(DATEDIFF(date2, date1))
FROM(
SELECT product, date1, date2
FROM myTable
WHERE product = 121
ORDER BY date2 DESC
LIMIT 3) tempTable;

Elegant mysql to select, group, combine multiple rows from one table

Here is a simplified version of my table:
group price spec
a 1 .
a 2 ..
b 1 ...
b 2
c .
. .
. .
I'd like to produce a result like this: (I'll refer to this as result_table)
price_a |spec_a |price_b |spec_b |price_c ...|total_cost
1 |. |1 |.. |... |
(min) (min) =1+1+...
Basically I want to:
select the rows containing the min price within each group
combine columns into a single row
I know this can be done using several queries and/or combined with some non-sql processing on the results, but I suspect that there maybe better solutions.
The reason that I want to do task 2 (combine columns into a single row)
is because I want to do something like the following with the result_table:
select *,
(result_table.total_cost + table1.price + table.2.price) as total_combined_cost
from result_table
right join table1
right join table2
This may be too much to ask for, so here is some other thoughts on the problem:
Instead of trying to combine multiple rows(task 2), store them in a temporary table
(which would be easier to calculate the total_cost using sum)
Feel free to drop any thoughts, don't have to be complete answer, I feel it's brilliant enough if you have an elegant way to do task 1 !
==Edited/Added 6 Feb 2012==
The goal of my program is to identify best combinations of items with minimal cost (and preferably possess higher utilitarian value at the same time).
Consider #ypercube's comment about large number of groups, temporary table seems to be the only feasible solution. And it is also pointed out there is no pivoting function in MySQL (although it can be implemented, it's not necessary to perform such operation).
Okay, after study #Johan's answer, I'm thinking about something like this for task 1:
select * from
(
select * from
result_table
order by price asc
) as ordered_table
group by group
;
Although looks dodgy, it seems to work.
==Edited/Added 7 Feb 2012==
Since there could be more than one combination may produce the same min value, I have modified my answer :
select result_table.* from
(
select * from
(
select * from
result_table
order by price asc
) as ordered_table
group by group
) as single_min_table
inner join result_table
on result_table.group = single_min_table.group
and result_table.price = single_min_table.price
;
However, I have just realised that there is another problem I need to deal with:
I can not ignore all the spec, since there is a provider property, items from different providers may or may not be able to be assembled together, so to be safe (and to simplify my problem) I decide to combine items from the same provider only, so the problem becomes:
For example if I have an initial table like this(with only 2 groups and 2 providers):
id group price spec provider
1 a 1 . x
2 a 2 .. y
3 a 3 ... y
4 b 1 ... y
5 b 2 x
6 b 3 z
I need to combine
id group price spec provider
1 a 1 . x
5 b 2 x
and
2 a 2 .. y
4 b 1 ... y
record (id 6) can be eliminated from the choices since it dose not have all the groups available.
So it's not necessarily to select only the min of each group, rather it's to select one from each group so that for each provider I have a minimal combined cost.
You cannot pivot in MySQL, but you can group results together.
The GROUP_CONCAT function will give you a result like this:
column A column B column c column d
groups specs prices sum(price)
a,b,c some,list,xyz 1,5,7 13
Here's a sample query:
(The query assumes you have a primary (or unique) key called id defined on the target table).
SELECT
GROUP_CONCAT(a.`group`) as groups
,GROUP_CONCAT(a.spec) as specs
,GROUP_CONCAT(a.min_price) as prices
,SUM(a.min_prices) as total_of_min_prices
FROM
( SELECT price, spec, `group` FROM table1
WHERE id IN
(SELECT MIN(id) as id FROM table1 GROUP BY `group` HAVING price = MIN(price))
) AS a
See: http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html
Producing the total_cost only:
SELECT SUM(min_price) AS total_cost
FROM
( SELECT MIN(price) AS min_price
FROM TableX
GROUP BY `group`
) AS grp
If a result set with the minimum prices returned in row (not in column) per group is fine, then your problem is of the gretaest-n-per-group type. There are various methods to solve it. Here's one:
SELECT tg.grp
tm.price AS min_price
tm.spec
FROM
( SELECT DISTINCT `group` AS grp
FROM TableX
) AS tg
JOIN
TableX AS tm
ON
tm.PK = --- the Primary Key of the table
( SELECT tmin.PK
FROM TableX AS tmin
WHERE tmin.`group` = tg.grp
ORDER BY tmin.price ASC
LIMIT 1
)