MySQL - Select values and remove duplicates by table name - mysql

I have two tables which have the same structure but another names (in first table I store default values, in second table I store saved values by user).
I select these values using union all:
SELECT * FROM `table_default` UNION ALL SELECT * FROM `table_saved`
Structure of table_default:
| ID | SOME_VAL |
| 1 | def_val |
| 2 | def_val |
| 3 | def_val |
Structure of table_saved:
| ID | SOME_VAL |
| 1 | test |
| 3 | text |
And now, when I using this query:
SELECT * FROM `table_default` UNION ALL SELECT * FROM `table_saved`
I got:
| ID | SOME_VAL |
| 1 | def_val |
| 2 | def_val |
| 3 | def_val |
| 1 | test |
| 3 | text |
But I want to get unique values by ID. Table_saved is more important so when select return duplicates I want to remove always record from table_default.
So finally I want to get:
| ID | SOME_VAL |
| 2 | def_val | --> from TABLE_DEFAULT because this record (by ID) is not exist in table_saved
| 1 | test | --> from TABLE_SAVED
| 3 | text | --> from TABLE_SAVED
I can't use GROUP BY id because I don't know which record will be remove (sometime GROUP BY remove duplicate from table_default but sometimes GROUP BY also remove duplicates from table_saved) so I can't manage this.
Is it possible to remove duplicates (something like GROUP BY) using table name and row name ? Or maybe somebody has another idea. Please help.
Thanks.

If I understand correctly, you want to always retain all records from table_saved, plus records from table_default having IDs not appearing in table_saved. One approach is to use a left join to find the unique records from table_default. Then union that with all records from table_saved.
SELECT t1.ID, t1.SOME_VAL
FROM table_default t1
LEFT JOIN table_saved t2
ON t1.ID = t2.ID
WHERE t2.ID IS NULL
UNION ALL
SELECT ID, SOME_VAL
FROM table_saved;

If a default value is always present you could use a LEFT JOIN and COALESCE:
SELECT d.ID, COALESCE(s.SOME_VAL, d.SOME_VAL) AS SOME_VAL
FROM table_default d
LEFT JOIN table_saved s USING(ID)

Related

Joining 2 sql table into one table

Im trying to link a list of ID to a list of date in SQL.
This is the data i have both in different table.
| Date | ID |
|2017-12-25| 1 |
|2017-12-26| 2 |
|2017-12-27| 3 |
I will like to merge this into
| Date | ID |
|2017-12-25| 1 |
|2017-12-25| 2 |
|2017-12-25| 3 |
|2017-12-26| 1 |
|2017-12-26| 2 |
|2017-12-26| 3 |
|2017-12-27| 1 |
|2017-12-27| 2 |
|2017-12-27| 3 |
I would use CROSS JOIN for SQL Server
select a.[date], t.id from table t
cross join
(
select * from table
)a
You'll probably want to MERGE
MERGE table1 <alias1>
USING table2 <alias2>
ON <alias1>.ID = <alias2>.ID
WHEN NOT MATCHED BY TARGET THEN
INSERT (ID, Date)
VALUES (<alias1>.ID, <alias1>.Date);
SELECT * FROM table1;

sql select with no duplicates in both columns

I want to select rows without duplicate values in columns. What I mean is that if there is a row with | 2 | 1 | and another one with | 1 | 2 | in the current selection, I want to show only one of them.
+------+------+
| id1 | id2 |
+------+------+
| 2 | 1 |
| 4 | 3 |
| 3 | 4 |
| 1 | 4 |
+------+------+
so in the example above it will select only first, last and either second OR third row.
and also to substitute these values with the string 'TITLE' from another table.
table values:
+----+----------+
| id | title |
+----+----------+
| 1 | title1 |
| 2 | title2 |
| 3 | title3 |
| 4 | title4 |
+----+----------+
so that the final select would have only titles in rows.
You can use least and greatest to do this. least gets the lower value of id1,id2 and greatest gets the greater of id1,id2.
select distinct least(id1,id2),greatest(id1,id2)
from t
Actually the above generates rows which aren't in the table. To avoid it, you need a left join with a derived table.
select t1.id1,t1.id2
from t t1
left join (select least(id1,id2) as id1,greatest(id1,id2) as id2
from t
group by least(id1,id2),greatest(id1,id2)
having count(*) > 1
) t2 on t2.id1=t1.id1 and t2.id2=t1.id2
where t2.id1 is null and t2.id2 is null
Edit: To get the title strings from a different table based on id's
select t1.id1,t1.id2,tt1.title,tt2.title
from t t1
left join (select least(id1,id2) as id1,greatest(id1,id2) as id2
from t
group by least(id1,id2),greatest(id1,id2)
having count(*) > 1
) t2 on t2.id1=t1.id1 and t2.id2=t1.id2
join titles tt1 on tt1.id=t1.id1 --use a left join if the titles table won't have all the id's
join titles tt2 on tt2.id=t1.id2 --use a left join if the titles table won't have all the id's
where t2.id1 is null and t2.id2 is null

Different behavior of mySql compare to Ms-Sql and Oracle on joining the table with sorted result set

The following 2 tables exist:
T1 :
---------------
| Id | Name |
---------------
| 1 | One |
| 2 | Two |
| 3 | Three |
---------------
T2:
----------------------
| Id | Name | T1Id |
----------------------
| 6 | X | 3 |
| 7 | Y | 2 |
| 8 | Z | 1 |
----------------------
Table one (T1) has the primary key column ‘Id’ with values 1, 2 and 3.
Table two (T2) has the primary key column ‘Id’ and also ‘T1Id’ foreign key column related to T1 table.
I’m trying to execute the following SQL command:
SELECT * FROM (SELECT * FROM T1 ORDER BY Id ASC) AS Tmp
INNER JOIN T2 ON Tmp.Id = T2.Level1Id
I’m wondering that although the first line is trying to order T1 and then join to T2 the result set is not sorted, the other DBMS s like Ms-SQL or Oracle do that.
The result set is:
Result:
----------------------------------------
| Id | Name | Id | T1Id | Name |
----------------------------------------
| 3 | Three | 6 | 3 | X |
| 2 | Two | 7 | 2 | Y |
| 1 | One | 8 | 1 | Z |
----------------------------------------
Why this happens and what’s the reason?
The SQL standard clearly says that the result set does not need to be in any particular order if you don't specify an ORDER BY for it.
Any "intermediate" ORDER BY on subselects or join inputs has no impact and can be ignored.
Without the specified ordering, the database is free to choose what order is most efficient to implement. That may in some cases be the same order as one of the join inputs (it would come out that way naturally in case of a nested loop join), but you cannot depend on that.
So if you want to get the result in a defined order, you have to put the ORDER BY on the top-most SELECT statement.
Try this
SELECT * FROM T1 AS Tmp
INNER JOIN T2 ON Tmp.Id = T2.Level1Id
ORDER BY Tmp.Id ASC

MySQL query to select group of IDs from one table, depending on query on a second table

I am sure this would be easy to google if I knew the right words to use, but I've tried and not come up with anything: apologies if this is a common question on SO.
I have one table which lists a set of records which can be one of 4 types.
table_1:
+-------+------------+------+
| id | value | type |
+-------+------------+------+
| 1 | x | 1 |
| 2 | y | 1 |
| 3 | z | 2 |
| 4 | a | 3 |
+-------+------------+------+
I have another table which references the id of this table and stores data
table_2:
+-------+------------+------+
| id | table_1_id |value |
+-------+------------+------+
| 1 | 4 | A |
| 2 | 2 | B |
| 3 | 3 | C |
| 4 | 2 | D |
+-------+------------+------+
I want to write a query that effects:
"Find all the records from table 1 which are of type 1, take the id's of those records, and find all the records in table 2 where 'table_1_id' which match one of that set of ids."
In the above very oversimplified table example that would result in the query returning records with ids 2 and 4 in table 2
Sounds like your looking for IN:
select *
from table2
where table_1_id in (select id from table1 where type = 1)
Or perhaps you could JOIN the tables:
select t2.*
from table2 t2
join table1 t1 on t2.table_1_id = t1.id
where t1.type = 1
Joining the tables could result in duplicate records. Depends on your needs.
SELECT t1.value,t1.type,t2.value FROM table1 t1,table2 t2 WHERE t1.id = t2.table_1_id AND t1.type = 1;

Join to same table several times in a single query?

I'm trying to get deeper into "advanced"-SQL'ing but have a slight problem with some pretty basic stuff.
I have one table, where one row refers to another row. There are of course unique id's as well but I'll skip those here:
+----------+----------------------------+
| field | name | value |
+----------+----------------------------+
| 1 | aa | 0 |
| 1 | ab | 0 |
| 2 | ba | 1 |
| 2 | bb | 1 |
| 3 | ca | 2 |
| 3 | cb | 2 |
+----------+----------------------------+
What I want to accomplish is to get field when I know field=3 and name= 'ca'.
I've tried something like this:
SELECT table.value AS parent_id FROM table WHERE table.field=3 AND table.name='ca'
That works at some point, it lists everything at 2:field, I need then to find value 1 from the field. BUT if the 2:field does not have any references (as above illustrated, 1:field) then I need the last value which will be 2:field.
How would that be possible in MySQL?
What you need is a self-join by using the same table TWICE in the same query, but different ALIAS...
select
t1.field,
t1.name,
t1.value as ThisIsYourParentKey,
t2.name as ParentName,
t2.value as GrandParentKey
from
YourTable t1
left join YourTable t2
on t1.value = t2.field
where
t1.name = 'a2'