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.
Related
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 |
I am using MySQL, and I'm a newbie!
Hope you guys here can help me with a SQL question.
Say I have 2 tables, and I want to a simple join.
Table 1:
id | service_id | user_number
----------------------------------------------------------------------
0 | 1001 | 10
1 | 1002 | 20
2 | 1004 | 40
Table 2:
id | service_id | error_number
----------------------------------------------------------------------
0 | 1001 | 1000
1 | 1003 | 3000
2 | 1004 | 4000
I want to do a join on service_id and have default value of user_number and error_number to be 0 if it does not exist.
So:
id | service_id | user_number | error_number
----------------------------------------------------------------------
0 | 1001 | 10 | 1000
1 | 1002 | 20 | 0
3 | 1003 | 0 | 3000
2 | 1004 | 40 | 4000
I tried some queries, but they kept giving me null instead of 0.
Thanks a lot.
Here you should use union first, then do aggregation:
select t.`service_id`, sum(t.`user_number`) as `user_number`, sum(t.`error_number`) as `error_number`
from (
select `service_id`, `user_number`, 0 as `error_number` from t1
union
select `service_id`, 0 as `user_number`, `error_number` from t2
) t
group by `service_id`
demo here.
You can try this one, mate:
SELECT
t1.id,
t1.service_id,
COALESCE(tb1.user_number, 0) `user_number`,
COALESCE(tb2.error_number, 0) `error_number`
FROM
(
SELECT id, service_id
FROM table1
UNION
SELECT id, service_id
FROM table2
) t1
LEFT JOIN table1 tb1 ON tb1.service_id = t1.service_id
LEFT JOIN table2 tb2 ON tb2.service_id = t1.service_id;
Try this:
select COALESCE(t1_service,t2_service ) as service_id, COALESCE(user_number,0) as user_number , COALESCE(error_number,0) as error_number
from (
select t1.service_id as t1_service , t1.user_number , t2.error_number, t2.service_id as t2_service
from table_1 t1
LEFT OUTER JOIN table_2 t2
on t1.service = t2.service
union
select t1.service_id as t1_service , t1.user_number , t2.error_number, t2.service_id as t2_service
from table_1 t1
Right OUTER JOIN table_2 t2
on t1.service = t2.service
)z1
order by service_id
Here is some dummy data:
| ID | CREATED AT |
| 367 | 2014-05-28 22:55:36 |
| 367 | 2014-05-28 22:57:06 |
| 369 | 2014-05-28 23:06:02 |
| 369 | 2014-05-28 23:08:05 |
| 369 | 2014-05-28 23:18:07 |
| 350 | 2014-05-28 23:12:56 |
| 261 | 2014-05-28 21:17:11 |
| 261 | 2014-05-29 22:27:43 |
What I'd like to select from this, are the IDs (obviously not a primary key in this case) where by the created_at date has a difference of 24hrs or more. So in the case with the above data, ID 261 has two records in there, which were created over 24hrs apart. So in the collection that is returned I'd want to see ID 261 in there.
What would be an effective way to structure this kind of query?
slower option
SELECT id, TIME_TO_SEC(TIMEDIFF(MAX(created_at),MIN(created_at))) as seconds_difference
FROM table
GROUP BY id
HAVING seconds_difference > 3600*24
faster option
SELECT t1.id, TIME_TO_SEC(TIMEDIFF(t2.created_at, t1.created_at) as seconds_difference
FROM table t1
INNER JOIN table t2 ON (t2.id = t1.id AND t2.created_at > t1.created_at)
WHERE TIME_TO_SEC(TIMEDIFF(t2.created_at, t1.created_at) > 3600*24
Easiest way to do is to use WHERE EXISTS with timestampdiff()
select ID
from test t1
where exists(
select 1 from test t2
where t1.ID = t2.ID
AND TIMESTAMPDIFF(HOUR,t1.`CREATED AT`,t2.`CREATED AT`) >=24
);
DEMO
This should work:
SELECT DISTINCT t1.`ID` FROM `tbl` t1
INNER JOIN `tbl` t2 ON t1.`ID`=t2.`ID`
WHERE t2.`CREATED_AT` <= t1.`CREATED_AT` - INTERVAL 24 HOUR;
Edit:
A better query (won't return a result if its min and max are 24 hours apart but there is something in the middle that is less than 24 hours apart):
SELECT DISTINCT t1.`ID` FROM `test` t1
INNER JOIN `test` t2 ON t1.`ID`=t2.`ID`
LEFT JOIN `test` t3 ON t3.`ID`=t1.`ID` AND t3.`CREATED_AT` != t1.`CREATED_AT` AND TIME_TO_SEC(TIMEDIFF(t3.`CREATED_AT`, t1.`CREATED_AT`)) <= 3600 * 24
WHERE TIME_TO_SEC(TIMEDIFF(t2.`CREATED_AT`, t1.`CREATED_AT`)) >= 3600 * 24 AND t3.ID IS NULL
i have 3 tables :
table1
code(Primary key) | name | quantity
B001 | sand | 50
B002 | nail | 100
B003 | paint | 10
=======
table2
code | qty_out
B001 | 2
B001 | 1
B001 | 20
B002 | 10
B002 | 30
=======
table3
code | qty_in
B001 | 1
B001 | 5
B002 | 5
B002 | 10
=======
Result that I want is:
table1
code | name | quantity | Out | In | total
B001 | sand | 50 | 23 | 6 | 33
B002 | nail | 100 | 40 | 15 | 75
B003 | paint | 10 | null/0 | null/0 | 10
I used this query :
SELECT table1.code, table1.name, table1.quantity, sum(table2.qty_out ) AS 'Out', sum( table3.qty_in ) AS 'In'
FROM table1
LEFT JOIN table2 ON table2.code = table1.code
LEFT JOIN table3 ON table3.code = table1.code
GROUP BY table1.code
ORDER BY table1.code ASC
In that query I get result like this...code B001 out 46 and in 18, code B002 out 80 and in 30, code B003 out null and in null
How to fix this?
use this query
select t.code,t.name,t.quantity,t.out,t.in,(t.out+t.in) as total
from (
SELECT table1.code, table1.name, table1.quantity,
( select sum(table2.qty_out)
from table2
where table1.code=table2.code ) as out,
( select sum(table3.qty_in)
from table3
where table3.code=table1.code ) as in
FROM table1
) as t
Using a subquery, a UNION clause and GROUPping, I built the following query :
SELECT
p.code,
p.name,
-- Using IFNULL to handle products without stock variation
IFNULL(SUM(q.q_in), 0) AS total_in,
IFNULL(SUM(q.q_out), 0) AS total_out,
-- Compute the new stock level
p.qty + IFNULL(SUM(q.q_in), 0) - IFNULL(SUM(q.q_out), 0) AS qty
FROM (
-- UNION (= concatenate) prod_in and prod_out tables
SELECT
product,
qty AS q_in,
0 AS q_out -- Enforce schema (otherwise, q_out is dropped)
FROM prod_in
UNION
SELECT
product,
0 AS q_in,
qty AS q_out
FROM prod_out
) AS q
-- Using a RIGHT join to show products without stock variations
RIGHT JOIN products AS p
ON p.code = q.product
-- Group by id to get the summarized view
GROUP BY q.product
Here's the query in a working SQLfiddle with your sample data
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