Create a Join leaving one row for any possible duplicate - mysql

I have a 2 tables that looks like this
How can I call the same column wihout duplicating it
TYSM for help

Please try below mentioned Query:
select distinct t2.data,t1.key,t1.data from t1.table1 JOIN table as t2 ON t1.key = t2.key

You could assign a row number using a variable to t2 then join to t1 supressing the output of the t1.key.
for example
drop table if exists t1,t2;
create table t1 (id int);
create table t2 (id int, name varchar(2));
insert into t1 values(1),(2),(3),(4);
insert into t2 values(1,'s1'),(1,'s2'),(2,'s3'),(3,'s4'),(4,'s5');
select s.id, s.name,
case when s.rn = 1 then s.rn
else ''
end as something
from t1
join
(
select t2.id,t2.name,
if(t2.id <> #p, #rn:=1,#rn:=#rn+1) rn,
#p:=t2.id
from t2,(select #rn:=0,#p:=0) r
) s on t1.id = s.id
order by t1.id, s.name
Result
+------+------+-----------+
| id | name | something |
+------+------+-----------+
| 1 | s1 | 1 |
| 1 | s2 | |
| 2 | s3 | 1 |
| 3 | s4 | 1 |
| 4 | s5 | 1 |
+------+------+-----------+
5 rows in set (0.00 sec)

Related

How to eliminate a specific row in mysql

id manager_id name
1 1 Tony
2 2 smith
3 2 harry
4 1 jack
5 1 william
6 2 steve
7 2 no name
8 2 john
9 2 no name
I used this query for get same last ordered id.
select t.*
from tablename t
where not exists (select 1
from tablename
where manager_id <> t.manager_id
and id > t.id)
| id | manager_id | name |
| --- | ---------- | ----- |
| 6 | 2 | steve |
| 7 | 2 | no name |
| 8 | 2 | john |
| 9 | 2 | no name |
The above query is working fine. but now my need is Eliminating the specific rows where name = no name. So how to customize the query.
Please use below query to eliminate no name,
select t.*
from tablename t
where not exists (select 1
from tablename
where manager_id <> t.manager_id
and id > t.id) and t.name != 'no name';
You could use a delete with inner join based on your query
delete t1 from tablename t1
inner join (
select t.*
from tablename t
where not exists (
select 1
from tablename where manager_id <> t.manager_id and id > t.id
)
) t2 on t1.id = t2.id
and t2.name ='no name'
or based on your comment could be you just want set the value to null
in this case you need update
Update tablename t1
inner join (
select t.*
from tablename t
where not exists (select 1 from tablename where manager_id <> t.manager_id and id > t.id)
) t2 on t1.id = t2.id
and t2.name = 'no name'
set t2.name = NULL

Display child and parent relationship (if any) in a same table

I have this table
| id |parent|name|
| 1 | NULL | E |
| 2 | NULL | B |
| 3 | 5 | U |
| 4 | 5 | X |
| 5 | NULL | C |
| 6 | NULL | A |
I would like the list, ordered by parent's name, of all ID whether they have a parent or not:
| id |parent|name|has_child|
| 6 | NULL | A | 0 |
| 2 | NULL | B | 0 |
| 5 | NULL | C | 1 |
| 3 | 5 | U | 0 |
| 4 | 5 | X | 0 |
| 1 | NULL | E | 0 |
Is it possible?
I have tried many things but never get the proper answer, and I don't really know how to add the 'has_child' column
SELECT
t1.parent,
t2.name
FROM tablename AS t1
INNER JOIN
(
SELECT MIN(id) AS id, parent
FROM tablename
GROUP BY parent
) AS t22 ON t22.id = t1.id AND t1.parent = t22.parent
INNER JOIN tablename AS t2 ON t1.parent = t2.id;
I would use a self join here:
SELECT DISTINCT
t1.id,
t1.parent,
t1.name,
1 - ISNULL(t2.id) has_child
FROM tablename t1
LEFT JOIN tablename t2
ON t1.id = t2.parent
ORDER BY
t1.id;
The join condition used here, which matches a given record as a parent to one or more children, is that the current id is also the parent of some other record(s). Note that we need SELECT DISTINCT here, because a given parent might match to more than one child record.
You can use a self join -- because you want the name of the parent and not the id -- and coalesce() for ordering:
select t.*,
(case when exists (select 1 from t tc where tc.parent = t.id)
then 1 else 0
end)
from t left join
t tp
on t.parent = tp.id
order by coalesce(tp.name, t.name), -- group rows by the parent, if any
(tp.name is null) desc, -- put parent first
t.name; -- order by children
I hope that you find this answer a little bit useful. The subquery gets the distinct id of parents and excludes the blanked fills.
SELECT *,
CASE WHEN id IN (SELECT DISTINCT parent
FROM tablename
WHERE parent IS NOT NULL)
THEN '1' ELSE '0'
END AS has_child
FROM tablename
ORDER BY name;
SELECT t1.id, t1.parent, t1.name, MAX(t2.parent is not null) has_child
FROM table t1
LEFT JOIN table t2 ON t1.id = t2.parent_id
GROUP BY t1.id, t1.parent, t1.name

How to select all rows from group, until occurrence of a value

I'm trying to extract all rows from same Group until I hit breakpoint value B. The example data below is ordered virtual table:
+----+--------+------------+
| ID | Group | Breakpoint |
+----+--------+------------+
| 1 | 1 | A |
| 2 | 1 | A |
| 3 | 1 | B |
| 4 | 1 | A |
| 5 | 2 | A |
| 6 | 2 | A |
| 7 | 2 | A |
| 8 | 3 | A |
| 9 | 3 | B |
+----+--------+------------+
This would be my result.
+----+--------+------------+
| ID | Group | Breakpoint |
+----+--------+------------+
| 1 | 1 | A |
| 2 | 1 | A |
| 5 | 2 | A |
| 6 | 2 | A |
| 7 | 2 | A |
| 8 | 3 | A |
+----+--------+------------+
Notice that when there are both A and B breakpoint values within a group, I want to have the rows until the first A value in this order. If there are only A values for a group like in group 2, I want to have all of the items in the group.
Here's a simple solution that uses no subqueries or GROUP BY logic.
SELECT t1.ID, t1.Group, t1.Breakpoint
FROM MyTable AS t1
LEFT OUTER JOIN MyTable AS t2
ON t1.ID >= t2.ID AND t1.`Group` = t2.`Group` AND t2.Breakpoint = 'B'
WHERE t2.ID IS NULL
For each row t1, try to find another row t2 with 'B', in the same Group, with an earlier ID. If none is found, the OUTER JOIN guarantees that t2.ID is NULL. That will be true only up until the desired breakpoint.
From you example above, you are not really grouping the results. you just need to display the records where Breakpoint is A:
Select * From Table
Where Breakpint ='A'
You may use NOT EXISTS
select *
from your_table t1
where not exists (
select 1
from your_table t2
where t1.group = t2.group and t2.id <= t1.id and t2.breakpoint = 'B'
)
or ALL can work as well if you never have NULL in id
select *
from your_table t1
where t1.id < ALL(
select t2.id
from your_table t2
where t1.group = t2.group and t2.breakpoint = 'B'
)
Assuming that we are ordering by ID column, we could do something like this:
SELECT d.*
FROM mytable d
LEFT
JOIN ( SELECT bp.group
, MIN(bp.id) AS bp_id
FROM mytable bp
WHERE bp.breakpoint = 'B'
GROUP BY bp.group
) b
ON b.group = d.group
WHERE b.bp_id > d.id OR b.bp_id IS NULL
ORDER BY d.group, d.id
This takes into account cases where there is no breakpoint='B' row for a given group, and returns all of the rows for that group.
Note that the inline view b gets us the lowest id value from rows with breakpoint='B' for each group. We can outer join that to original table (matching on group), and then conditional tests in the WHERE clause to exclude rows that follow the first breakpoint='B' for each group.
SQL tables represent unordered sets. Hence, there is no "before" or "after" a particular row.
Let me assume that you have some column that specifies the ordering. I'll call it id. You can then do what you want with:
select t.*
from t
where t.id < (select min(t2.id) from t t2 where t2.group = t.group and t2.breakpoint = 'B');
To get all rows when if there are no 'B':
select t.*
from t
where t.id < (select coalesce(min(t2.id), t.id + 1) from t t2 where t2.group = t.group and t2.breakpoint = 'B');

Count records in one table where there are no records in linked table matching certain criteria

I have 2 tables:
T1:
id | name
------ | ------
1 | Bob
2 | John
3 | Joe
T2:
id | T1_id | type
------ | ------ | ------
1 | 1 | call
2 | 1 | email
3 | 1 | fax
4 | 2 | call
5 | 2 | email
6 | 2 | fax
7 | 3 | call
8 | 3 | email
I want to count the number of records in T1 which do not have a record in T2 with a type of 'fax'.
So the answer in this case would be 1 (3|Joe)
Currently I have:
SELECT count(*)
FROM `T1`
JOIN `T2` on `T1`.`id` = `T2`.`T1_id`
WHERE `T2`.`type` != 'fax'
But this is obviously counting all the records which are not 'fax'. I just cant get the logic in my head.
Any help would be appreciated!
A subquery is unnecessary:
SELECT COUNT(DISTINCT t1.id)
FROM t1
LEFT
JOIN t2
ON t2.t1_id = t1.id
AND t2.type = 'fax'
WHERE t2.id IS NULL;
select count(*)
from
(
SELECT t1.id
FROM T1
LEFT JOIN T2 on T1.id = T2.T1_id
GROUP BY t1.id
HAVING sum(T2.type = 'fax') = 0
) tmp
The answers given by Strawberry and juergen d are correct, but for completeness, here's another example using NOT EXISTS. All the queries will have different execution plans, so depending on your data in T1 and T2 YMMV:
SELECT COUNT(*)
FROM `T1`
WHERE NOT EXISTS (
SELECT *
FROM `T2`
WHERE `T2`.`T1_id` = `T1`.`id`
AND `T2`.`type` = 'fax'
)

How to show parent record Id in child record column-Mysql

I want to show my parent id with child record(duplicate record). Here is my table
ID|Name |Comments|
__|_____|________|_
1 |Test1|Unique |
2 |Test2|Unique |
3 |Test1|Unique |
4 |Test2|Unique |
5 |Test1|Unique |
6 |Test3|Unique |
Expected Result:
ID|Name |Comments |
__|_____|__________________|_
1 |Test1|Unique |
2 |Test2|Unique |
3 |Test1|Duplicate with: 1 |
4 |Test2|Duplicate with: 2 |
5 |Test1|Duplicate with: 1 |
6 |Test3|Unique |
not sure what the exact goal here, but here is a single query that get the job done:
mysql> select ID,tbl.Name,if(no!=ID,concat('Duplicate with: ',no),'Unique') Comments from tbl left join (select ID no,Name from tbl group by Name) T on T.Name=tbl.Name;
+----+-------+-------------------+
| ID | Name | Comments |
+----+-------+-------------------+
| 1 | Test1 | Unique |
| 2 | Test2 | Unique |
| 3 | Test1 | Duplicate with: 1 |
| 4 | Test2 | Duplicate with: 2 |
| 5 | Test1 | Duplicate with: 1 |
| 6 | Test3 | Unique |
+----+-------+-------------------+
Check This Live Demo using 'coalesce' and 'Case when'
Query :
select id
,name
,coalesce(
( select coalesce(case when min(id)>0 then concat('Duplicate with : ',min(id)) else null end,Comments)
from Yourtable t2 where t2.name = t.name and t2.id < t.id group by Comments)
,Comments) as Comments
from Yourtable t
order by id
Output :
hey you can try this query and it is giving expected result.
select t1.id,t1.`name`,
CASE WHEN (select count(`name`) from table_name t2 where t2.`name` = t1.`name` and t2.id <= t1.id ) = 1
then 'unique'
else CONCAT('Duplicate with :',(select min(t3.id) from table_name t3 where t3.name = t1.`name`))
end as 'comments'
from table_name t1
replace table_name with your table.
Hope this works for you. Ask if any doubt
Using only a single sub-query.
select id
,name
,coalesce
(
concat
(
'Duplicate with: '
,(select min(id) from mytable t2 where t2.name = t.name and t2.id < t.id)
)
,'Unique'
) as Comments
from mytable t
order by id