Odd behavior of max and having in MySQL when max==0 - mysql

I have the following table:
mysql> select * from foo;
| id | value | bar |
+----+-------+------+
| 1 | 2 | 3 |
| 2 | 0 | 3 |
| 1 | 1 | 5 |
I want to select the tuple with the maximum value for each id. However, when max(value) is 0, I don't get a result.
mysql> select id,max(value),bar from foo group by id having max(value);
| id | max(value) | bar |
+----+------------+------+
| 1 | 2 | 3 |
Is this supposed to behave like that and if so, why?

HAVING cannot be used in any way to pick a record out of a group of records as defined by the fields used in the GROUP BY clause. It is rather applied to the group as a whole.
So, in your case, you have to do a self-join to get the rest of the table fields:
select t1.id, t1.value, t1...
from foo as t1
join (
select id, max(value) as max_value
from foo
group by id
) as t2 on t1.id = t2.id and t1.value = t2.max_value

IMHO you can get MAX couple by multiplying (id x value).
create table foo(id int, value int);
insert into foo values
(2,0),
(1,0),
(2,1),
(3,0),
(2,2);
select id, value
from foo
order by (id * value) desc
limit 1;
id | value
2 | 2
drop table foo;

Related

Display row of another table as column of current table

Consider there are two tables:
Table1:
**Result Total**
Pass 102
Fail 3
Undetermined 1
Table 2:
**Pass% Fail% Undetermined%**
96.23 2.83 0.94
Result Needed:
**Result Total Percentage**
Pass 102 96.23
Fail 3 2.83
Undetermined 1 0.94
How to convert the table 2 rows as column in table 1 to obtain the result ?
first, You can try to do unpivot on Table2, then JOIN with Table1.
Your sql-server version is 2008, you can use unpivot by UNION ALL.
CREATE TABLE T1(
Result VARCHAR(50),
Total int
);
CREATE TABLE T2(
Pass FLOAT,
Fail FLOAT,
Undetermined FLOAT
);
insert into T2 VALUES (96.23,2.83,0.94)
INSERT INTO T1 VALUES ('Pass',102);
INSERT INTO T1 VALUES ('Fail',3);
INSERT INTO T1 VALUES ('Undetermined',1);
Query 1:
SELECT t1.*,s.val
FROM (
SELECT Pass val,'PASS' Name
FROM T2
UNION ALL
SELECT Fail val,'Fail' Name
FROM T2
UNION ALL
SELECT Undetermined val,'Undetermined' Name
FROM T2
) s inner join T1 t1 on t1.Result = s.Name
Results:
| Result | Total | val |
|--------------|-------|-------|
| Pass | 102 | 96.23 |
| Fail | 3 | 2.83 |
| Undetermined | 1 | 0.94 |
If you can use CROSS APPLY with VALUE you can try this.
Query:
SELECT t1.*,s.val
FROM (
SELECT v.* FROM T2
CROSS APPLY(VALUES
(Pass,'PASS'),
(Fail,'Fail'),
(Undetermined,'Undetermined')
) v(val,Name)
) s inner join T1 t1 on t1.Result = s.Name
Results:
| Result | Total | val |
|--------------|-------|-------|
| Pass | 102 | 96.23 |
| Fail | 3 | 2.83 |
| Undetermined | 1 | 0.94 |

Join related Issue

New to SQL
Suppose we have two tables
One has got the ID and Name column :
+----+-------+
| ID | Name |
+----+-------+
| 1 | Sam |
| 1 | Dan |
+----+-------+
and the second one has also got two columns as follow :
+----+------------+
| ID | Relatives |
+----+------------+
| 1 | Uncle |
| 2 | Aunty |
+----+------------+
If we do inner join we would only get the rows where the condition satisfies. But i want the output to be Like
+------+------------+
| ID | Relatives |
+------+------------+
| 1 | Uncle |
| NULL | Aunty |
+------+------------+
once only the value in the ID column should be shown. If the occurrence is twice or thrice it should come as null.
Just tell me if it is possible or not? and How for both the cases.
As your question is not clear, so assuming that you need to retrieve id from table a and name from table b and you also want to avoid duplicate rows, then an option could be to use distinct along with left join:
select distinct a.id, b.name
from b
left outer join a
on b.id = a.id
order by id desc
Result:
+------+-------+
| id | name |
+------+-------+
| 1 | Uncle |
| NULL | Aunty |
+------+-------+
DEMO
Try this:
SELECT
T1.Id,
T2.Relatives
FROM SecondTable T2
LEFT JOIN FirstTable T1
ON T1.ID = T2.ID
GROUP BY T1.Id,
T2.Relatives
This is what I get exactly:
CREATE TABLE #a (
id int,
name varchar(10)
)
CREATE TABLE #b (
id int,
name varchar(10)
)
INSERT INTO #a
VALUES (1, 'sam')
INSERT INTO #a
VALUES (1, 'Dan')
INSERT INTO #b
VALUES (1, 'Uncle')
INSERT INTO #b
VALUES (2, 'Aunty')
SELECT
T1.Id,
T2.name
FROM #b T2
LEFT JOIN #a T1
ON T1.ID = T2.ID
GROUP BY T1.Id,
T2.name
DROP TABLE #a
DROP TABLE #b
Output:
Id name
NULL Aunty
1 Uncle
Hope, this is what you ask in your question.

Mysql select N of X duplicates, omitting 1 duplicate

Considering this table:
+-----+--------+
| id | value |
+-----+--------+
| 1 | 22 |
+-----+--------+
| 2 | 12 |
+-----+--------+
| 3 | 22 |
+-----+--------+
| 4 | 22 |
+-----+ -------+
I can select all where the column value is duplicated like so:
select value from table having count(value) > 1 ;
This will output the Ids 1,3 and 4.
What I'm attempting to do is select where duplicates, but leaving 1 (one) duplicate un selected, so the above would output only the Ids 3 and 4 (or 1 and 3 etc... the duplicate omitted does not matter, only that it is.
How can I achieve this?
This question IS NOT a duplicate of
Using LIMIT within GROUP BY to get N results per group?
You could use an aggregatio function for filter a value for id and the select all the others
select * from table
where (value, id) not in (
select value, max(id)
from table
group by value
having count(value) > 1
)
;
You can do either as:
select *
from test t1
where exists (select 1
from test t2
where t2.value = t1.value
having count(value)>1)
limit 2
OR:
select t1.*
from test t1 inner join
(select value from test t2 having count(value)>1) t2
on t1.value = t2.value
limit 2;

Preserve order of SQL WHERE IN() clause with nested SELECT

I need a list of item names ordered by count of items. Item names and corresponing id's are stored in tabletwo while tableone refers to items by id's:
tableone tabletwo
+--------+-----------+ +----+------+
| itemid | condition | | id | name |
+--------+-----------+ +----+------+
| 2 | satisfied | | 1 | foo |
+--------+-----------+ +----+------+
| 1 | satisfied | | 2 | bar |
+--------+-----------+ +----+------+
| 3 | satisfied | | 3 | hurr |
+--------+-----------+ +----+------+
| 3 | satisfied | | 4 | durr |
+--------+-----------+ +----+------+
| 3 | satisfied |
+--------+-----------+
| 4 | satisfied |
+--------+-----------+
| 4 | satisfied |
+--------+-----------+
| 3 | nope |
+--------+-----------+
| 1 | satisfied |
+--------+-----------+
SQL code:
SELECT `itemname` FROM `tabletwo` WHERE `id` IN (
SELECT `itemid` FROM (
SELECT count(`itemid`), `itemid`
FROM `tableone`
WHERE `some_codition`="satisfied"
GROUP BY `itemid`
ORDER BY count(`itemid`) DESC
) alias
)
The nested SELECT returns a list of item id's in descendant order: 3, 4, 1, 2. This list is then used as an argument of an IN() clause. The expected result of the whole query is: hurr, durr, foo, bar (in this exact order). But the order is not preserved. I know it can be done like this: ORDER BY FIELD(id, 3, 4, 1, 2) but I don't know how to do this trick when the ordered list is fetched dynamically like in my case. Do I need to SELECT it again? Or temporary table maybe? Or is it better to build another query outside SQL?
Try using JOIN instead:
SELECT t2.`itemname`
FROM `tabletwo` AS t2
JOIN (
SELECT count(`itemid`) AS cnt, `itemid`
FROM `tableone`
WHERE `some_codition`="satisfied"
GROUP BY `itemid`
) AS t1 ON t1.`itemid` = t2.`id`
ORDER BY t1.cnt DESC
You can create a derived table using the subquery of the IN operator and perform a JOIN to this table, so that you are able to use the COUNT in the ORDER BY clause of the main query.
Use JOIN instead of IN:
SELECT
t2.name
FROM tabletwo t2
LEFT JOIN tableone t1
ON t1.itemid = t2.id
AND t1.`condition` = 'satisfied'
GROUP BY
t2.id, t2.name
ORDER BY COUNT(*) DESC
If you want to exclude rows from tabletwo that do not have a match on tableone, use INNER JOIN instead of LEFT JOIN.
ONLINE DEMO

Why is this two table into one table union, where showing invalid result in MySQL?

I have a table1 (records 3), and table2 (records 3).
Where i have field name in both.
Now i want to make a result from those two table
which will show me both table records and take only one if there is duplicate.
from that result i will do main query using like or or other logical statements
So my expected output records will contain 5 rows not 6 rows. How do i do that?
Example:
table1: table2:
+-------------------------+ +--------------------------------+
| Name | ID | Name | ID
+-------------------------- +---------------------------------
| A | 1 | 1 December Name | 4
| B | 2 | D | 5
| 1 December Name | 3 | E | 6
My Expected output is following which works, but does not work when i use WHERE
like to only get '1 December Name':
+-----------------------------------------------------+
| Name | ID
+-----------------------------------------------------
| A | 1 table1
| B | 2 table1
| 1 December Name | 3 table2 or table1 (no unique)
| D | 4 table2
| E | 5 table2
I tried this:
SELECT * FROM
(
(
SELECT name AS name FROM table1
)
UNION
(
SELECT anothername AS name FROM table2
)
) as t
WHERE name like '%1 December Name%'
limit 1,10
Output: Your SQL query has been executed successfully ( Query took 0.2798 sec )
Problem: The following query has no error but it does not find that record which contain '1 December Name'
Follow up: works i know now which ID it used
SELECT NAME, ID, STATUS FROM
(
(
SELECT NAME AS name , id, CONCAT('table1') AS STATUS FROM table1
)
UNION ALL
(
SELECT ANOTHERNAME AS name, id, CONCAT( 'table2' ) AS STATUS FROM table2
)
) AS t
WHERE
t.NAME LIKE '%1 December Name%'
LIMIT 1 , 10;
You can get something similar to what you want:
select name, group_concat(id) from
(select name, 'table1' as id from table1
union all
select name, 'table2' from table2) x
group by name
Output would be:
+------------------------------------+
| Name | ID
--------------------------------------
| A | table1
| B | table1
| 1 December Name | table1,table2
| D | table2
| E | table2
UNION ALL is the right choice (not UNION), because it does not remove duplicates, and preserves row order
Try this
(SELECT name FROM table1 )
UNION (SELECT name FROM table2);