how to remove rows that are related to same values - mysql

how do I turn this:
| ID | LETTER
----------------
| 1 | A
| 2 | B
| 3 | B
| 4 | C
| 5 | D
| 6 | D
| 7 | F
| 8 | A
On this:
| ID | LETTER
----------------
| 4 | C
| 7 | F

There are multiple ways to solve this problem, one possible way is -
SELECT
*
FROM
t_system_log;
SELECT
t_table.*
FROM
t_table,
(
SELECT
letter
FROM
t_table
GROUP BY
letter
HAVING
count(letter) = 1) AS t_unique
WHERE
t_table.letter = t_unique.letter
;
My Fiddle

I'm using SQL 5.6,
If the table name is t_name,
Then simplest query to remove rows that are related to same values:
*
SELECT * FROM t_name
Group by LETTER having count(LETTER)=1;

Related

MySQL JOIN on using substring from one table

I'm trying to join two tables together in MySQL. I need to join based on the full string from one field (Table a:ID) and the sub-string from the other table (Table b:caseID). A mock-up of the table structure can be seen at the bottom of this post. ID and caseID are defined as unique.
The output I'm looking for is similar to:
|-------------|--------------|------------|
| ID | name | age |
|-------------|--------------|------------|
| 1 | Bob | 22 |
| 2 | Bill | 23 |
| 3 | Ben | 24 |
|-------------|--------------|------------|
I know how to extract a substring based on a delimiter:
SELECT SUBSTRING(caseID, LOCATE('-', caseID)+1, LENGTH(caseID)) AS ExtractString FROM b
but I'm unclear how to combine this with the usual SQL JOIN statement to return all joined records. I keep getting error like 'returns more than one row'.
Any help much appreciated.
Table a:
|-------------|--------------|
| ID | name |
|-------------|--------------|
| 1 | Bob |
| 2 | Bill |
| 3 | Ben |
|-------------|--------------|
Table b:
|-------------|--------------|
| caseID | age |
|-------------|--------------|
| 24-1 | 22 |
| 24-2 | 23 |
| 24-3 | 24 |
|-------------|--------------|
SELECT *
FROM a
LEFT JOIN b ON a.ID = SUBSTRING(b.caseID, LOCATE('-', b.caseID)+1, LENGTH(b.caseID))
SELECT *
FROM a
JOIN b ON a.ID = SUBSTRING_INDEX(b.caseID, '-', -1)
Typical, as soon as I ask the question I work out the answer!
SELECT a.*, b.*
FROM a
JOIN b
ON b.id = SUBSTRING(a.caseID, LOCATE('-', a.caseID)+1, LENGTH(a.caseID))

MySQL - How get this result?

I have a two tables.
work:
+----+----------+
| id | position |
+----+----------+
| 1 | 1 |
| 2 | 2 |
+----+----------+
content:
+----+---------+------+-------------+
| id | work_id | name | translation |
+----+---------+------+-------------+
| 1 | 1 | Kot | 1 |
| 2 | 1 | Cat | 2 |
| 3 | 2 | Ptak | 1 |
| 4 | 2 | Bird | 2 |
| 5 | 2 | Ssss | 3 |
+----+---------+------+-------------+
I want to get result like this:
+----+------+----------+
| id | name | sortName |
+----+------+----------+
| 1 | Kot | NULL |
| 1 | Cat | NULL |
| 2 | Ptak | Ssss |
| 2 | Bird | Ssss |
+----+------+----------+
My not working query is here:
select
w.id,
c.name,
cSort.name as sortName
from
work w
LEFT JOIN
content c
ON
(w.id=c.work_id)
LEFT JOIN
content cSort
ON
(w.id=cSort.work_id)
WHERE
c.translation IN(1,2) AND
cSort.translation=3
ORDER BY
sortName
I want to get for each work at least one translation and secound if exist (translation=1 always exist). And for every row I want special column with translation used to sort. But Not always this translation exist for work.id. In this example I want to sort work by translation=3.
Sorry for my not fluent english. Any ideas?
Best regards
/*
create table work ( id int, position int);
insert into work values
( 1 , 1 ),
( 2 , 2 );
create table content(id int, work_id int, name varchar(4), translation int);
insert into content values
( 1 , 1 , 'Kot' , 1),
( 2 , 1 , 'Cat' , 2),
( 3 , 2 , 'Ptak' , 1),
( 4 , 2 , 'Bird' , 2),
( 5 , 2 , 'Ssss' , 3);
*/
select w.id,c.name,(select c.name from content c where c.work_id = w.id and c.translation = 3) sortname
from work w
join content c on w.id = c.work_id
where c.translation <> 3;
result
+------+------+----------+
| id | name | sortname |
+------+------+----------+
| 1 | Kot | NULL |
| 1 | Cat | NULL |
| 2 | Ptak | Ssss |
| 2 | Bird | Ssss |
+------+------+----------+
So translation is also a work_id and you consider translation = 3 a translation in your example and translation <> 3 an original. You want to join each original record with every translation record where the latter's work_id matches the former's translation.
I think you are simply confusing IDs here. It should be ON (w.translation = cSort.work_id).
Another way to write the query:
select o.work_id as id, o.name, t.name as sortname
from (select * from content where translation <> 3) o
left join (select * from content where translation = 3) t
on t.work_id = o.translation
order by t.name;
There seems to be no need to join table work.
I'd like to add that the table design is a bit confusing. Somehow it is not clear from it what is a translation for what. In your example you interpret translation 3 as a translation for the non-three records, but this is just an example as you say. I don't find this readable.
UPDATE: In order to sort your results by work.position, you can join that table or use a subquery instead. Here is the order by clause for the latter:
order by (select position from work w where w.id = o.work_id);

if with yes or no status mysql query

I have 2 tables, the first table or_f_table data. The second table or_table
or_f_table
f_id | f_o_id | f_u_id
1 | 19 | 1
2 | 5 | 2
3 | 19 | 2
or_table
o_id | o_name
4 | test1
5 | test2
19 | oops2
20 | oops3
SELECT o.o_name,
IF ((SELECT count(*) FROM or_f_table as f
WHERE f.f_u_id = 1 ),'Yes','No') as follow_status
FROM or_table as o
WHERE o.o_name LIKE '%oop%'
I want to do something like this result :-
o_name | follow_status
oops2 | Yes
oops3 | No
I am getting result
o_name | follow_status
oops2 | Yes
oops3 | Yes
Why doesn't it work? And how should I correct it
There will always be a value greater than 0 for your where condition. That is why it is not working.
Try this to get the specified results
SELECT o.o_name,
IF ((SELECT count(*) FROM or_f_table as f
WHERE f.f_o_id = o.o_id ),'Yes','No') as follow_status
FROM or_table as o
WHERE o.o_name LIKE '%oop%'

Select rows based on 2 columns

I am not the greatest at SQL and I am trying to achieve the following:
I have a table with columns like so:
id | cup_type | cup_id | name
I have a ton of records in the database which will have the same cup_id but different cup_types
I would really like to select records that have the same cup_id but different cup_types
id | cup_type | cup_id | name
1 | TypeOne | 12 | NameOne
2 | TypeTwo | 12 | NameTwo
3 | TypeOne | 13 | NameThree
4 | TypeTwo | 13 | NameFour
5 | TypeOne | 14 | NameFive
6 | TypeOne | 14 | NameSix
When I run the said query it would being me back the following:
id | cup_type | cup_id | name
1 | TypeOne | 12 | NameOne
2 | TypeTwo | 12 | NameTwo
3 | TypeOne | 13 | NameThree
4 | TypeTwo | 13 | NameFour
I hope I have explained this ok and let me know if more clarity is needed.
This query would do the trick
select * from
yourtable a
join (select cup_id, count(distinct cup_type) nbType
from yourTable
group by cup_id) b using(cup_id)
where b.nbType >= 2;
Get a result set from your table where you count the distinct cup_type.
Group that result set by cup_id.
Keep the cup_id so we can join on the same table, using that id.
Return only those where the count of distinct types was at least two.
Try something like this:
select a.id, b.id ....... from t1 as a, t2 as b where a.cup_id=b.cup_id and a.cup_type !=b.cup_type

select lower and upper from lower only table

How can I transform a normalized table with family, name and 'lowerbound' number to a result set with family, name, lower and upper bound, where upper bound is defined as min(lowerbound of family) > current lowerbound and if no number like this exists, use a provided number
for example, if this is the schema and data:
create table records(
family varchar(10),
name varchar(10),
lowbound int(4)
);
insert into records
values
('letters', 'a',1),('letters', 'b',3),('letters', 'c',3),('letters', 'd',3),
('letters', 'e',7),('letters', 'f',7),('numbers', '12',1), ('numbers', '15',1), ('numbers', '18',4);
and the provided number is 9, then the result set should be:
| FAMILY | NAME | LOWER | UPPER |
|---------|------|-------|-------|
| letters | a | 1 | 3 |
| letters | b | 3 | 7 |
| letters | c | 3 | 7 |
| letters | d | 3 | 7 |
| letters | e | 7 | 9 |
| letters | f | 7 | 9 |
| numbers | 12 | 1 | 4 |
| numbers | 15 | 1 | 4 |
| numbers | 18 | 4 | 9 |
Try this out:
SELECT r1.family, r1.name, r1.lowbound lower, coalesce(min(r2.lowbound), 9) upper
FROM records r1
LEFT JOIN records r2 ON r1.family = r2.family AND r1.lowbound < r2.lowbound
GROUP BY r1.family, r1.name, r1.lowbound
Fiddle here
I think the easiest way to express this is with a correlated subquery in the select clause:
select r.*,
coalesce((select r2.lowbound
from records r2
where r2.family = r.family and
r2.lowbound > r.lowbound
order by r2.lowbound
limit 1
), 9) as highbound
from records r;
The coalesce() handles the case where there is no value. In that case, your substitution value of 9 is used.
Here is the SQL Fiddle.