I have table "s_msgs" and his structure is
id | from | to
------------------
1 | John | Robert
2 | John | Michael
3 | Robert | John
4 | Michael | John
I need obtain every message sender-recipient couple, that is result must be
John | Robert
John | Michael
I write query, but I think this is not optimal variant, all the more so expected that in table will be several milion rows, so can anyone tell more optimal query?
this is my query
SELECT `from`,`to` FROM s_msgs WHERE id IN(
SELECT id FROM (
SELECT MIN(id) AS id,
CASE
WHEN STRCMP(`to`,`from`) = -1 THEN CONCAT(`to`,`from`)
ELSE CONCAT(`from`,`to`)
END
AS conc
FROM s_msgs
GROUP BY conc
) AS t
)
How about
SELECT DISTINCT `from`, `to`
FROM YOUR_TABLE
UNION
SELECT DISTINCT `to`,`from`
FROm YOUR_TABLE
EDIT
Got a new one, was the ID that saved me.
Have a look at this demo
SQL Fiddle DEMO
SELECT *
FROM MY_TABLE f
WHERE NOT EXISTS (
SELECT 1
FROM MY_TABLE t
WHERE f.`from` = t.`to`
AND f.`to` = t.`from`
AND f.id > t.id)
Related
I have fought my way through various answers and did some progress, however, the final solution has not been discovered.
The DB situation:
Table "clients_a":
userid | name
1 | Steve
2 | John
3 | Paul
Table "clients_b":
userid | name
1 | NULL
3 | Jokename
4 | Jessy
Desired result/output:
userid | name
1 | Steve
2 | John
3 | Paul
4 | Jessy
Description of what is going on:
userid is unique in the result (merged)
a result for name that is not NULL is favored
if two entries, then result from table clients_a is favored
all entries have a groupid (see below), that has to be taken into account
MySql queries I tried (and came close):
Attempt 1: This query works, but it does not regard the name. It takes all names from client_a:
SELECT * FROM
(
SELECT userid, name
FROM `client_a`
WHERE groupid = 123
UNION DISTINCT
SELECT userid, name
FROM `client_b`
WHERE groupid = 123
) AS res
GROUP BY res.userid
Attempt 2: This query creates duplicate entries (one userid can occur twice), but regards the name, as it seems:
SELECT o.*, i.* FROM
(
SELECT userid, name
FROM `client_a`
WHERE groupid = 123
UNION DISTINCT
SELECT userid, realname
FROM `client_b`
WHERE groupid = 123
GROUP BY userid
) AS o
LEFT JOIN `client_a` as i on i.userid = o.userid
I also tried to use MIN(name) without success.
Any help is appreciated.
You can do it with NOT EXISTS:
SELECT a.userid, a.name
FROM clients_a a
WHERE a.groupid = 123
AND (name IS NOT NULL OR NOT EXISTS (SELECT 1 FROM clients_b b WHERE b.userid = a.userid))
UNION
SELECT b.userid, b.name
FROM clients_b b
WHERE b.groupid = 123
AND NOT EXISTS (SELECT 1 FROM clients_a a WHERE a.userid = b.userid AND a.name IS NOT NULL)
See the demo.
Results:
userid
name
1
Steve
2
John
3
Paul
4
Jessy
I want to return 1 row for each letter in the alphabet. For example the table below goes from names a to z. In the production database i have 1000s of names.
id| name
1 | amy
2 | anna
3 | barry
4 | blake
5 | baron
6 | charles
I want a query to return 1 row for each letter. I know how to accomplish this with UNION but how do i accomplish this in a single query without UNION?
SELECT * FROM `table` WHERE name LIKE 'a%' LIMIT 1
UNION
SELECT * FROM `table` WHERE name LIKE 'b%' LIMIT 1
UNION
SELECT * FROM `table` WHERE name LIKE 'c%' LIMIT 1
UNION
SELECT * FROM `table` WHERE name LIKE 'd%' LIMIT 1
I'm expecting results returned:
[0]=>amy
[1]=>barry
[2]=>charles
You need to group by the first character.
SELECT name
FROM names
GROUP BY SUBSTRING(name, 1, 1);
See DEMO
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id SERIAL PRIMARY KEY
,name VARCHAR(20) NOT NULL UNIQUE
);
INSERT INTO my_table VALUES
(1,'amy'),
(2,'anna'),
(3,'barry'),
(4,'blake'),
(5,'baron'),
(6,'charles');
SELECT x.*
FROM my_table x
JOIN
( SELECT MIN(id) id
FROM my_table
GROUP
BY LEFT(name,1)
) y
ON y.id = x.id;
+----+---------+
| id | name |
+----+---------+
| 1 | amy |
| 3 | barry |
| 6 | charles |
+----+---------+
You could do an aggregate and group by perhaps;
select * from
(
select max(id) as maxid, substring(name,1,1) as first letter from tablename
group by substring(name,1,1)
) t1
join tablename t on t.id = t1.maxid
I have this MYSQL table:
Name | Age | X
--------------------
Andrew | 7 |
Andrew | 7 |
Andrew | 10 |
John | 9 |
John | 11 |
John | 11 |
And I would like to assign a value to those names that share age, like this:
Name | Age | X
--------------------
Andrew | 7 | x
Andrew | 7 | x
Andrew | 10 |
John | 9 |
John | 11 | x
John | 11 | x
Have no idea how to do it.
If your database supports window functions then
Select Name,Age,
case when count(Age)over(partition by Name, Age) > 1 then 'x' else '' end as X
FROM yourtable
If no(Mysql), then
Select Name,Age,
case when (select count(Age) from yourtable b where a.Name = b.Name and a.Age = b.Age) > 1 then 'x' else '' end as X
FROM yourtable a
As MySQL doesn't support window functions, you must read the table twice. Here is one way to do this:
select name, age, dups.x
from persons p
left join
(
select name, age, 'x' as x
from persons
group by name, age
having count(*) > 1
) dups using (name, age)
order by name, age;
--detecting duplicate column with all columns
with cte as
(select name, age ,x , row_number () over (partition by name,age,x order by
name) RowNum from Table
) select name,age,x from cte where rownum > 1
For sure this one will work .Just try it ...:). Easy and sensible!
Select Name,Age,count(*)
INTO #TempTable
FROM yourtable
group by Name,Age
having count(*) >1
update a
set a.X= "X"
from yourtable a
join #TempTable b on a.Name=b.Name and a.Age =b.Age
drop table #TempTable
I have the following data:
Name ID Date
Dave | 123 | 1-2-2011
Jim | 123 | 1-3-2011
Mike | 123 | 1-10-2011
Bill | 111 | 1-2-2011
Henry | 222 | 1-3-2011
Larry | 222 | 1-4-2011
I need a delete query to reduce this to:
Jim | 123 | 1-3-2011
Mike | 123 | 1-10-2011
Bill | 111 | 1-2-2011
Larry | 222 | 1-4-2011
i.e. I want to keep the two latest records for each ID.
I tried this:
Delete FROM UserTable a
WHERE
Date <> (SELECT MAX(Date) FROM UserTable b WHERE a.ID = b.ID)
AND ID IN (SELECT ID FROM UserTable GROUP BY ID HAVING COUNT(*) > 1)
but this retains only the latest 1 unique records.
Try something of the sort:
SELECT col1, col2, col3, COUNT(*)
FROM (SELECT DISTINCT * FROM your_TableName) AS T1
GROUP BY col2, col3
try using this code below depending on what you want to request try using ASC or DESC
SELECT column_name,column_name
FROM table_name
ORDER BY column_name,column_name ASC|DESC;
Try also reading up on your sql http://www.w3schools.com/sql/sql_orderby.asp
Partition over can be used to retain more than one duplicate.
delete from UserTable
where (id, date) in (
select id,date from (
select id,date,
row_number() over (partition by id order by date desc) as temp
from UserTable)
where temp > 2
);
This query adds another column with row number partitioned by the id, ordered by date and then deletes those records which have row number greater than 2.
assume following data:
Data:
id | date | name | grade
--------+---------------+-----------+---------------
1 | 2010/12/03 | Mike | 12
2 | 2010/12/04 | Jenny | 12
3 | 2010/12/04 | Ronald | 15
4 | 2010/12/03 | Yeni | 11
i want to know who has the best grade in each day, something like this:
Desired Result:
id | date | name | grade
--------+---------------+-----------+---------------
1 | 2010/12/03 | Mike | 12
3 | 2010/12/04 | Ronald | 15
i thought query should look like this:
SELECT name FROM mytable
GROUP BY date
ORDER BY grade DESC
but it returns something like this:
Current Unwanted Result:
id | date | name | grade
--------+---------------+-----------+---------------
1 | 2010/12/03 | Mike | 12
2 | 2010/12/04 | Jenny | 12
i searched and i found the reason:
GROUP BY happens before ORDER BY so it does not see and can't apply ORDER.
so how can i apply ORDER on GROUP BY?
Note: please keep in mind that i need the most simple query, because my query is actually very complex, i know i can achieve this result by some subquery or JOINing, but i want to know how to apply ORDER to GROUP BY. thanks
I used Oracle for this example, but the SQL should work in mysql (you may need to tweak the to_date stuff to work with mysql). You really need a subquery here to do what you are asking.
CREATE TABLE mytable (ID NUMBER, dt DATE, NAME VARCHAR2(25), grade NUMBER);
INSERT INTO mytable VALUES(1,to_date('2010-12-03','YYYY-MM-DD'),'Mike',12);
INSERT INTO mytable VALUES(1,to_date('2010-12-04','YYYY-MM-DD'),'Jenny',12);
INSERT INTO mytable VALUES(1,to_date('2010-12-04','YYYY-MM-DD'),'Ronald',15);
INSERT INTO mytable VALUES(1,to_date('2010-12-03','YYYY-MM-DD'),'Yeni',11);
SELECT id
, dt
, name
, grade
FROM mytable t1
WHERE grade = (SELECT max(grade)
FROM mytable t2
WHERE t1.dt = t2.dt)
ORDER BY dt
Results:
ID DT NAME GRADE
1 12/3/2010 Mike 12
2 12/4/2010 Ronald 15
I know you said you wanted a GROUP / ORDER only solution but you will need to use a subquery in this instance. The simplest way would be something like this:
SELECT id, date, name, grade
FROM mytable t1
WHERE grade =
(SELECT MAX(t2.grade) FROM mytable t2 WHERE t1.id = t2.id)
This would show multiple students if they shared the highest grade for the day.