Just get one data if duplicate (not DISTINCT) - mysql

I have the following result from a query in mysql (headers: depicao, arricao):
EDDH, EDDK
EDFH, EDDL
EDDS, EDDH
EDDK, EDDH
My problem is now, that I just want one of the rows, IF the data exist in the correlation "EDDH - EDDK" AND "EDDK - EDDH".
The query for this result is something like this:
SELECT DISTINCT p.depicao, p.arricao FROM xyz WHERE xxyyzz = 1
Thanks for your help!

Order the columns in a consistent way with GREATEST and LEAST, then use SELECT DISTINCT to remove duplicates.
SELECT DISTINCT GREATEST(depicao, arricao) as col1, LEAST(depicao, arricao) AS col2
FROM xyz
WHERE ...

I think row_number() does what you want:
select p.*
from (select p.*,
row_number() over (partition by least(p.depicao, p.arricao), greatest(p.depicao, p.arricao) order by rand()) as seqnum
from p
) p
where seqnum = 1;
You can add additional filtering conditions in the subquery, which you seem to have in your query but not your question.

Related

How to select matching results with other random results in mysql

I want to select all the matching results in a database table with also random results but with the matching results being at the top. With the way, I am doing now I am using two queries first one being the matching query, and if the count is zero I now select random results. I would like to do this with just one query.
You could attempt using a UNION ALL query as follows.
select product_name,price
from marketing_table
where price >=5000 /*user supplied filter*/
and price <=10000 /*user supplied filter*/
union all
select m.product_name,m.price
from marketing_table m
where not exists (select *
from marketing_table m1
where m1.price >=5000 /*user supplied filter*/
and m1.price <=10000 /*user supplied filter*/
)
What I understand from you comment, you may try something simple like this first:
SET #product := 'purse'; -- search term
SELECT * FROM product
ORDER BY product_name LIKE CONCAT('%',#product,'%') DESC, price ASC;
This is the simplest I can think of and it could be a starting point for you.
Here's a demo : https://www.db-fiddle.com/f/31jrR27dFJqYQQigzBqLcs/2
If this is not what you want, you have to edit your question and insert some example data with expected output. Your current question tend to be flagged as too broad and need focus/clarity.
Did you try using a UNION subquery with a LIMIT?
SELECT *
FROM (
SELECT 0 priority, t.*
FROM first_table t
UNION ALL
SELECT 1 priority, t.*
FROM second_table t
)
ORDER BY priority
LIMIT 20
If you do not want to include any second_table records if first_table returns, you would need to do a subquery on the second query to confirm that no rows exist.
SELECT *
FROM (
SELECT 0 priority, t.*
FROM first_table t
UNION ALL
SELECT 1 priority, t.*
FROM second_table t
LEFT JOIN (SELECT ... FROM first_table) a
WHERE a.id IS NULL
)
ORDER BY priority
LIMIT 20
I think it would be possible to use the Common Table Expressions (CTE) feature in MySQL 8, if you are using that version.
https://dev.mysql.com/doc/refman/8.0/en/with.html

The last value using GROUP BY

I need to take the last value from table where can_id equal.
So I've tried this SQL query
SELECT com.text, com.can_id
FROM (SELECT * FROM comments ORDER BY id DESC) as com
GROUP BY com.can_id
But if I change ASC / DESC in the first select, the second select will just group without sorting and take the value with the first id
This select will be used like left join in the query.
Example:
I need to get com.text with value "text2" (lasts)
If you are on MySql 8, you can use row_number:
SELECT com.text, com.can_id
FROM (SELECT comments.*,
row_number() over (partition by can_id order by id desc) rn
FROM comments) as com
WHERE rn = 1;
If you are on MySql 5.6+, you can (ab)use group_concat:
SELECT SUBSTRING_INDEX(group_concat(text order by id desc), ',', 1),
can_id
FROM comments
GROUP BY can_id;
In any version of MySQL, the following will work:
SELECT c.*
FROM comments c
WHERE c.id = (SELECT MAX(c2.id)
FROM comments c2
WHERE c2.can_id = c.can_id
);
With an index on comments(can_id, id), this should also have the best performance.
This is better than a group by approach because it can make use of an index and is not limited by some internal limitation on intermediate string lengths.
This should have better performance than row_number() because it does not assign a row number to each row, only then to filter things out.
The order by clause in the inner select is redundant since it's being used as a table, and tables in a relational database are unordered by nature.
While other databases such as SQL Server will treat is as an error, I guess MySql simply ignores it.
I think you are looking for something like this:
SELECT text, can_id
FROM comments
ORDER BY id DESC
LIMIT 1
This way you get the text and can_id associated with the highest id value.

Is efficient the following SQL query?

Exist a better way to do what the following SQL query does? I have the feeling that table1 will be searched twice and may be that can be avoided with some trick and increase the efficient of the query, but I just can't figure out how ;( Here is the query (in MySQL):
SELECT a, SUM(count)
FROM table1
GROUP BY a
HAVING SUM(count) = (SELECT SUM(count) as total FROM table1 GROUP BY a ORDER BY total DESC LIMIT 1)
The goal is return the number(s) with the major accumulate, with its accumulate.
being table1 a two field table like:
a,count
1,10
1,30
1,0
2,1
2,100
2,4
3,10
4,50
4,55
The result with that data sample is:
2,105
4,105
Thanks in advance.
SELECT a, total FROM
(SELECT a AS a, SUM(COUNT) AS total
FROM table1
GROUP BY a) AS xyz
HAVING total = MAX(total)
Hope this will work for you
This sub-query is executed only once, and you don't have to bother with creating any pre-query as other answers may suggest (although doing so this is still correct, just not needed). Database engine will realise, that the sub-query is not using any variable dependent on the other part of the query. You can use EXPLAIN to see how the query is executed.
More on the topic in this answer:
https://stackoverflow.com/a/658954/1821029
I think you could probably do it by moving your HAVING sub-select query into its on prequery. Since it will always include a single row, you won't require any "JOIN", and it does not have to keep recomputing the COUNT(*) every time the HAVING is applied. Do it once, then the rest
SELECT
a,
SUM(count)
FROM
table1,
( SELECT SUM(count) as total
FROM table1
GROUP BY a
ORDER BY total DESC
LIMIT 1 ) PreQuery
GROUP BY
a
HAVING
SUM(count) = PreQuery.Total
This query return one row with two columns:
1- a list of comma separated values of "a" column, which have the biggest "Total"
2- and the biggest Total value
select group_concat(a), Total
from
(select a, sum(count) as Total
from table1
group by a) OnTableQuery
group by Total
order by Total desc
limit 1
Note that it queries table1 just one time. The query was already tested.

where not in subquery - SQL Server 2008

The inner query in the following SQL statement is to normalize part of the database (code1, code2, code3, etc.) With the outer query I want to select the codes that aren't in the lookup table (tblicd)
select primarycode from
(
select id, primarycode from myTable
union
select id, secondarycode from myTable
union
select id, tertiarycode from myTable) as t
order by id
where primarycode not in tblicd.icd_id
The query above doesn't run, I'm wondering what I'm doing wrong. The error I get is the multi-part identifier tblicd.icd_id could not be bound
One problem is your ORDER BY and WHERE clauses are reversed. The ORDER BY clause must come after the WHERE clause.
Your WHERE clause is also incorrect. It should be like this:
WHERE primarycode NOT IN (SELECT icd_id FROM tblicd)
ORDER BY id
where primarycode not in tblicd.icd_id
might be
where primarycode not in (SELECT icd_id FROM tblicd )

mysql union statement with order by

I'am trying to understand what causes the following, maybe you could help me:
I have a query like:
select field1,fieldDate from table1
union all
select field1,fieldDate from table2
order by fieldDate desc
and the another one like this:
select field1,field2,fieldDate from table1
union all
select field1,field2,fieldDate from table2
order by fieldDate desc
So basically they are the same with the exception that in the second I retrieve an extra field.
Now, both results come with a diferent ordering, but just for the cases that the dates are exacly the same. For example there are 2 rows (row1,row2) with date 2009-11-25 09:41:55. For query 1 row1 comes before row2 and for query 2 row2 comes before row1.
Does somebody knows why this happens?
Thanks,
Regards
The ordering based on any fields that you don't explicitly order by is undefined, and the optimizer can change the ordering if it thinks that results in a better execution plan. Given two rows with the exact same value in the order by field you can not depend on them being in any particularly order in relation to each other unless you explicitly order by another field with different values.
Can you do this
select * from ( select
field1,field2,fieldDate, 0 as ordercol from table1
union all select
field1,field2,fieldDate, 1 as ordercol from table2) t1
order by fieldDate desc, ordercol asc
Straight from the MySQl manual, to user order by on a union you have to parenthesis the individual tables.
(select field1,fieldDate from table1)
union all
(select field1,fieldDate from table2)
order by fieldDate desc
This is not SQL standards compliant! The code you entered should order the union of both tables but to my surprise MySQL has the above syntax.
The order in which rows with the same fieldDate are returned can differ for each query execution. Usually this order will be the same but you should not count on it. If you want any extra ordering state more order by fields.
EDIT: This answer is wrong: the order by works on the entire union. I'll leave it here to save others the trouble :)
Your order by only works on the second part of the union. You can use a subquery to make the order by work on the entire union:
select field1,field2,fieldDate
from (
select field1,field2,fieldDate
from table1
union all
select field1,field2,fieldDate
from table2
) SubQueryName
order by fieldDate desc