I need to merge two tables:
Both have a primary key-column date, but with different values (different time intervals).
Both have different (unknown) columns: I don't know the names of the columns (same column-name may occur in both tables), I don't know how many columns, but all of the same type.
An example:
table1
date | colA | colB | colC
2011-02-02 | 1.09 | 1.03 | 1.04
table2
date | col1 | col2 | col3 | col4
2011-02-03 | 1.03 | 1.02 | 1.07 | 1.03
the result of the query should look like this:
tableResult
date | colA | colB | colC | col1 | col2 | col3 | col4
2011-02-02 | 1.09 | 1.03 | 1.04 | null | null | null | null
2011-02-03 | null | null | null | 1.03 | 1.02 | 1.07 | 1.03
This will not work:
INNER JOIN because it will only return the intersection between table1 and table2,
OUTER JOIN returns intersection + values only from left table (or right table if right join is used)
UNION because the count of columns may differ.
Any Ideas?
Christoph
You can create a temp table with the union of just the date column, and then use the temp table to left outer join with the other 2.
Example:
DROP TABLE temptbl IF EXISTS;
CREATE TEMPORARY TABLE temptbl (myDate DATETIME PRIMARY KEY)
AS (SELECT MyDate FROM table1)
UNION (SELECT MyDate FROM table2)
ORDER BY MyDate;
SELECT * FROM temptbl
LEFT OUTER JOIN table1 USING (MyDate)
LEFT OUTER JOIN table2 USING (MyDate);
select coalesce(t2.data,'')+coalesce(t1.data,'') as data,
t2.col1, t2.col2, t2.col3 ,t2.col4 ,t1.cola ,t1.colb, t1.colc
from table2 as t2
full outer join
table1 t1
on t2.data = 2011-02-03
or t1.data = 2011-02-02
Related
i have table with 2 columns like below
+----------+----------+
| Column A | Column B |
+----------+----------+
| 123 | ABC |
| 123 | XYC |
| 123 | FGH |
| 145 | QWE |
| 147 | YUI |
+----------+----------+
I want to select all values from table but view it like below:
+----------+---------+---------+----------+
| Column A | value 1 | value 2 | value 3 |
+----------+---------+---------+----------+
| 123 | ABC | XYC | FGH |
| 145 | QWE | | |
| 147 | YUI | | |
+----------+---------+---------+----------+
If you're not trying to create extra columns in your output, you can simply use GROUP_CONCAT with the separator of your choice. For example:
SELECT `Column A`,
GROUP_CONCAT(`Column B` SEPARATOR ' | ') AS `Values`
FROM table1
GROUP BY `Column A`
Output:
Column A Values
123 ABC | XYC | FGH
145 QWE
147 YUI
Demo on dbfiddle
I'm not sure how are you going to execute the query? but if you can manage to create dynamic SQL query string to find all duplicates rows and insert each row into a temp table and other values (unique) into a separate temp table. Then create another query to join all temp tables (with duplicate) value into a new data set, union all of them with the (unique) data set.
It may be a long and not a good solution but here's my experiment:
Insert all duplicates rows into #temp tables (3 rows= 3 #temp tables)
SELECT Id,Name
INTO #temp1
FROM TestTable
WHERE Name='ABC'
SELECT Id,Name
INTO #temp2
FROM TestTable
WHERE Name='XYC'
SELECT Id,Name
INTO #temp3
FROM TestTable
WHERE Name='FGH'
Insert all unique rows into single #temptable
SELECT Id,Name
INTO #temp4
FROM TestTable
WHERE Id!=123
Query
SELECT t1.Id,t1.Name as Value1,t2.Name as Value2,t3.Name as Value3
FROM #temp1 t1
INNER JOIN #temp2 t2 on t1.Id=t2.Id
INNER JOIN #temp3 t3 on t1.Id=t3.Id
UNION ALL
SELECT t4.Id,t4.Name as Value1,null as Value2,null as Value3
FROM #temp4 t4
Result
If you want three different columns, you can use row_number() and conditional aggregation:
select a,
max(case when seqnum = 1 then b end) as b_1,
max(case when seqnum = 2 then b end) as b_2,
max(case when seqnum = 3 then b end) as b_3
from (select t.*,
row_number() over (partition by a order by b) as seqnum
from t
) t
group by a;
I am looking for a way to create a relative relevance function when looking for values in two (or more) different tables. So I have tables like this
table1:
id weight
1 0.1
2 0.15
3 0.12
6 0.21
table2:
id weight
3 0.09
6 0.2
8 0.1
11 0.13
I need to get a relevance function from these two tables by merging them. Same row ids will get 10x relevance and rows with ids from only one table will get "weight" relevance.
Here is an intermediate table which I need to get (and my question is HOW to make such a table):
id1 weight1 id2 weight2
1 0.1 null null
2 0.15 null null
3 0.12 3 0.09
6 0.21 6 0.2
null null 8 0.1
null null 11 0.13
Using this table I can calculate the relevance whatever I need, but the problem is to create such table from these two. Could you help me?
I tried with LEFT JOIN, STRAIGHT_JOIN, LEFT OUTER JOIN, but they make very different results.
Edit: If it matters, I presently envisage the final table to look something like this:
id relevance
1 0.1
2 0.15
3 2.1
6 4.1
8 0.1
11 0.13
You can use FULL OUTER JOIN for this, e.g.:
SELECT t1.id AS id1, t1.weight AS weight1, t2.id AS id2, t2.weight AS weight2
FROM table1 t1 LEFT JOIN table2 t2 ON t1.id = t2.id
UNION
SELECT t1.id AS id1, t1.weight AS weight1, t2.id AS id2, t2.weight AS weight2
FROM table1 t1 RIGHT JOIN table2 t2 ON t1.id = t2.id;
Here's a few examples :
create table Table1 (
id int primary key not null,
weight decimal(10,2) not null default 0
);
create table Table2 (
id int primary key not null,
weight decimal(10,2) not null default 0
);
insert into Table1 (id, weight) values
(1, 0.10)
,(2, 0.15)
,(3, 0.12)
,(6, 0.21)
;
insert into Table2 (id, weight) values
(3, 0.09)
,(6, 0.20)
,(8, 0.10)
,(11, 0.13)
;
select
id12.id as id,
t1.id as id1,
t1.weight as weight1,
t2.id as id2,
t2.weight as weight2
from (select id from Table1 union select id from Table2) id12
left join Table1 t1 on t1.id = id12.id
left join Table2 t2 on t2.id = id12.id
;
id | id1 | weight1 | id2 | weight2
-: | ---: | ------: | ---: | ------:
1 | 1 | 0.10 | null | null
2 | 2 | 0.15 | null | null
3 | 3 | 0.12 | 3 | 0.09
6 | 6 | 0.21 | 6 | 0.20
8 | null | null | 8 | 0.10
11 | null | null | 11 | 0.13
select
id12.id as id,
coalesce(t1.weight,0) + coalesce(t2.weight,0) as relevance
from (select id from Table1 union select id from Table2) id12
left join Table1 t1 on t1.id = id12.id
left join Table2 t2 on t2.id = id12.id
order by id12.id;
id | relevance
-: | --------:
1 | 0.10
2 | 0.15
3 | 0.21
6 | 0.41
8 | 0.10
11 | 0.13
select id, sum(weight) as relevance
from
(
select id, weight from Table1
union all
select id, weight from Table2
) q
group by id
order by id;
id | relevance
-: | --------:
1 | 0.10
2 | 0.15
3 | 0.21
6 | 0.41
8 | 0.10
11 | 0.13
db<>fiddle here
The 2nd & 3th queries return the same result.
Which is better?
That would depend on how many extra fields and/or extra calculations are required.
SELECT id
, SUM(weight) * CASE WHEN COUNT(*)=1 THEN 1 ELSE 10 END relevance
FROM
( SELECT id
, weight
FROM table1
UNION
ALL
SELECT id
, weight
FROM table2
) x
GROUP
BY id;
+----+-----------+
| id | relevance |
+----+-----------+
| 1 | 0.10 |
| 2 | 0.15 |
| 3 | 2.10 |
| 6 | 4.10 |
| 8 | 0.10 |
| 11 | 0.13 |
+----+-----------+
We can use stored procedures and temporary tables to get solution
CREATE PROCEDURE GetReleavance()
BEGIN
Create TEMPORARY TABLE tmpList ENGINE=MEMORY
SELECT id, weight from t1
union all
SELECT id, weight from t2
union all
SELECT id, weight from t3;
select id, sum(weight)* POW(10,COUNT(1)-1) as relevance
from tmpList
group by id;
DROP TEMPORARY TABLE IF EXISTS tmpList;
END
In the procedure creating a temporary table with all id's and weight from different table and get sum(weight) based on id.
Call the stored procedure using
CALL GetReleavance()
You can make Union all for number of table you want also it will not make major impact on performance.
Consider there are two tables:
Table1:
**Result Total**
Pass 102
Fail 3
Undetermined 1
Table 2:
**Pass% Fail% Undetermined%**
96.23 2.83 0.94
Result Needed:
**Result Total Percentage**
Pass 102 96.23
Fail 3 2.83
Undetermined 1 0.94
How to convert the table 2 rows as column in table 1 to obtain the result ?
first, You can try to do unpivot on Table2, then JOIN with Table1.
Your sql-server version is 2008, you can use unpivot by UNION ALL.
CREATE TABLE T1(
Result VARCHAR(50),
Total int
);
CREATE TABLE T2(
Pass FLOAT,
Fail FLOAT,
Undetermined FLOAT
);
insert into T2 VALUES (96.23,2.83,0.94)
INSERT INTO T1 VALUES ('Pass',102);
INSERT INTO T1 VALUES ('Fail',3);
INSERT INTO T1 VALUES ('Undetermined',1);
Query 1:
SELECT t1.*,s.val
FROM (
SELECT Pass val,'PASS' Name
FROM T2
UNION ALL
SELECT Fail val,'Fail' Name
FROM T2
UNION ALL
SELECT Undetermined val,'Undetermined' Name
FROM T2
) s inner join T1 t1 on t1.Result = s.Name
Results:
| Result | Total | val |
|--------------|-------|-------|
| Pass | 102 | 96.23 |
| Fail | 3 | 2.83 |
| Undetermined | 1 | 0.94 |
If you can use CROSS APPLY with VALUE you can try this.
Query:
SELECT t1.*,s.val
FROM (
SELECT v.* FROM T2
CROSS APPLY(VALUES
(Pass,'PASS'),
(Fail,'Fail'),
(Undetermined,'Undetermined')
) v(val,Name)
) s inner join T1 t1 on t1.Result = s.Name
Results:
| Result | Total | val |
|--------------|-------|-------|
| Pass | 102 | 96.23 |
| Fail | 3 | 2.83 |
| Undetermined | 1 | 0.94 |
Copy 1st 2 rows in same table and insert it with edited column as shown below.
Table 1 (ID is auto increment)
ID | CL1 | CL2 | CL3
1 | A | text1 | NULL
2 | B | text2 | NULL
Table 2
ID | CL3
21 | 45
24 | 63
Converted Table 1
ID | CL1 | CL2 | CL3
1 | A | text1 | NULL
2 | B | text2 | NULL
3 | A | text1 | 45
4 | B | text2 | 63
I know how to copy and insert all the rows with one column duplicated, but changing some column with different value is the problem.
Below is the query to copy all fields with 1 column changed:
INSERT INTO table1 (col1, col2, col3)
SELECT col1, col2, 1
FROM table1 LIMIT 2;
Ex: So now we have table2 which has table1 CL3's values. Now can we get the data from another table and insert them while copying?
Assuming you want the first 2 records from 1 table updated with the values from the 1st 2 rows from another table, then I think you will need to add a sequence number to each one and join based on that.
Something like as follows, but it won't be quick!
INSERT INTO table1 (ID, CL1, CL2, CL3)
SELECT NULL, a.CL1, a.CL2, b.CL3
FROM
(
SELECT CL1, CL2, #cnt1:=#cnt1 + 1 AS cnt
FROM table1
CROSS JOIN (SELECT #cnt1:=0) sub0
ORDER BY ID
LIMIT 2
) a
INNER JOIN
(
SELECT CL3, #cnt2:=#cnt2 + 1 AS cnt
FROM table2
CROSS JOIN (SELECT #cnt2:=0) sub0
ORDER BY ID
LIMIT 2
) b
ON a.cnt = b.cnt
First, sorry if the title is confusing.
SQL is not my strong suit and I've been working on this for a while, my thoughts at the mmoment is something with a join, and group maybe.
Soto Example:
record | type | key1 | key2 | data1
---------------------------------------
1 | 1 | joe | smoe | 10
2 | 2 | homer | simpson | 20
3 | 1 | null | null | 30
4 | 3 | bart | simpson | 40
Where primary key is made up of id, key1, key2.
I only want rows of 'type' WHERE key1 is not null AND key2 is not null.
So since in record 3, type 1 has null keys, I therefore want all records of type 1 to not be included in the derived table.
Here's a correlated, "not exists" approach:
select *
from T as t1
where not exists (
select *
from T as t2
where t2.type = t1.type and (t2.key1 is null or t2.key2 is null)
)
And here's one that uses a non-correlated query along with grouping. Perhaps it's what you had in mind:
select *
from T as t1
where t1.type in (
select t2.type
from T as t2
group by t2.type
having count(*) = count(t2.key1) and count(*) = count(t2.key2)
)
Since I understand mysql query plans can be sensitive to these things. Here's the equivalent with a join:
select t1.*
from T as t1
inner join
(
select t2.type
from T as t2
group by t2.type
having count(*) = count(t2.key1) and count(*) = count(t2.key2)
) as goodtypes
on goodtypes.type = t1.type