Combining Tables in MySQL to replace NULL values when rows match - mysql

I have an issue where different pieces of information on customers are found in completely different servers.
My solution so far is to take the necessary pieces from each server and combine them in MySQL.
My problem:
I'm looking to replace NULL values from one table in MySQL with information from another table when NULL in the first table, provided other columns match.
Information will only appear in the second table when the columns appear as NULL in the OrderName column and -1 in the Order_ID column from the original table. This second table will have the missing information and will align with other columns such as Cust_ID and DateTime.
E.g.
Table1:
Cust_ID | Order_ID | OrderName | DateTime | Other_Info
------------------------------------------------------------------------------
12345 | -1 | NULL | 2016/01/01 | Info1
12345 | 1254 | Orange | 2016/02/03 | Info2
54321 | 5412 | Apple | 2016/04/15 | Info3
45899 | -1 | NULL | 2016/06/08 | Info4
Table2:
Cust_ID | OrderID | OrderName | DateTime
-------------------------------------------------------------
12345 | 1549 | Banana | 2016/01/01
45899 | 5862 | Grape | 2016/06/08
Desired output:
Cust_ID | Order_ID | OrderName | DateTime | Other_Info
------------------------------------------------------------------------------
12345 | 1549 | Banana | 2016/01/01 | Info1
12345 | 1254 | Orange | 2016/02/03 | Info2
54321 | 5412 | Apple | 2016/04/15 | Info3
45899 | 5862 | Grape | 2016/06/08 | Info4
I have tried using CASE WHEN clauses combined with COALESCE function to achieve this with no success as of yet.
Is this possible to do in MySQL?
If so, any guidance on how to achieve this would be greatly appreciated.
Thanks for your help.

Use CASE EXPRESSION with a LEFT JOIN :
SELECT t1.cust_id,
CASE WHEN t1.order_id = -1 THEN t2.orderid else t1.order_id END as order_id,
CASE WHEN t1.orderName IS NULL THEN t2.orderName else t1.orderName END as order_Name,
t1.dateTime,
t1.other_info
FROM Table1 t
LEFT JOIN Table2 s
ON(t.cust_id = s.cust_id)

LEFT JOIN with CASE condition can get your required data.
SELECT T1.CUST_ID,
CASE WHEN T1.ORDER_NAME IS NULL THEN T2.ORDER_ID ELSE T1.ORDER_ID END,
CASE WHEN T1.ORDER_NAME IS NULL THEN T2.ORDER_NAME ELSE T1.ORDER_NAME END,
T1._DATE_TIME,
T1.OTHER_INFO
FROM
TABLE1 T1
LEFT JOIN TABLE2 T2
ON T1.CUST_ID = T2.CUST_ID;

You are looking for left join:
select t1.cust_id, coalesce(t2.orderid, t1.order_id) as order_id,
coalesce(t2.order_name, t1.order_name) as order_name,
t1.datetime, t1.other_info
from table1 t1 left join
table2 t2
on t1.cust_id = t2.cust_id and
t1.datetime = t2.datetime and
t1.order_id = -1;

Related

mysql join only if a field has a particular value

I am trying to fetch a table on certain conditions with join. My table is:
tab_registrations
--------------------------------------------
reg_id |familyid| familyname | parent_id |
| | | |
-------|--------|-------------|-----------|
1 | 2 | null | null |
-------|--------|-------------|-----------|
2 | others | abc | 3 |
-------|--------|-------------|-----------|
3 | 3 | null | null |
-------|--------|-------------|-----------|
4 | others | def | 2 |
-------|--------|-------------|-----------|
tab_family
-------------------------------------
family_id | family_name | parent_id |
| | |
-------------------------------------
1 | tyu | 0 |
-------------------------------------
2 | xyz | 1 |
-------------------------------------
3 | mno | 2 |
-------------------------------------
I want to join these tables on:
if tab_registrations.family not equal to null, then select corresponding parent_id from tab_family
SELECT tab_registration.*,tab_family.family_id,tab_family.parent_id
FROM `tab_registration`
join tab_family on tab_registration.family_id = tab_family.family_id
WHERE reg_id = 1
if tab_registrations.family is equal to 'others', then select tab_registrations.familyname and tab_registrations.parent_id
When I try the above query if tab_registrations.family = 'others', no rows fetched
How can I achieve this? Can anyone help me?
Change to LEFT JOIN with the condition that tab_registration.familyid is not equal to others. Also, you can use conditional CASE..WHEN statements to get the familyname and parent_id values.
SELECT tr.*,
CASE WHEN tr.familyid = 'others' THEN tr.familyname
ELSE tf.family_name
END AS familyname,
CASE WHEN tr.familyid = 'others' THEN tr.parent_id
ELSE tf.parent_id
END AS parent_id
FROM tab_registration tr
LEFT JOIN tab_family tf
ON tr.family_id = tf.family_id AND
tr.familyid <> 'others'
WHERE tr.reg_id = 1
For multi-table queries, it if preferable to use Aliasing for code clarity and readability.
may be useful this query
SELECT tr.*,tf.family_id,tf.parent_id,
IF(tr.familyid='others',tr.familyname,tf.family_name) as fname
IF(tr.familyid='others',tr.parent_id,tf.parent_id) as parentId
FROM `tab_registration` tr
left join tab_family tf on tr.family_id = tf.family_id

MySQL Dynamic Pivot Table Select Most Recent Timestamp

I've been working with a dynamic pivot table in MySQL as referenced here, which works fine. In my situation, my table also has a timestamp column. I want to return the most recent values in the pivot table for the attributes and I can't figure out how to accomplish this. So consider the example table data:
+----+---------+---------------+--------+------------+
| id | item_id | property_name | value  | timestamp |
+----+---------+---------------+--------+------------+
|  1 |       1 | color         | blue   | 2018-01-01 |
|  2 |       1 | size          | large  | 2018-01-01 |
|  3 |       1 | weight        | 65     | 2018-01-01 |
<SNIP>
| 15 |       1 | color         | purple | 2018-02-01 |
| 16 |       1 | weight        | 69     | 2018-02-01 |
+----+---------+---------------+--------+------------|
For item_id '1' the result row should be:
+---------+--------+--------+--------+
| item_id | color  | size   | weight |
+---------+--------+--------+--------+
|       1 | purple | large  | 69     |
+---------+--------+--------+--------+
Thanks in advance!
Your question is slightly tricky. We can use a subquery to find the most recent record for each item and property. Then, join your table to this subquery and do a regular pivot query to generate the output you want.
SELECT
t1.item_id,
MAX(CASE WHEN t1.property_name = 'color' THEN t1.value END) AS color,
MAX(CASE WHEN t1.property_name = 'size' THEN t1.value END) AS size,
MAX(CASE WHEN t1.property_name = 'weight' THEN t1.value END) AS weight
FROM yourTable t1
INNER JOIN
(
SELECT item_id, property_name, MAX(timestamp) AS max_timestamp
FROM yourTable
GROUP BY item_id, property_name
) t2
ON t1.item_id = t2.item_id AND
t1.property_name = t2.property_name AND
t1.timestamp = t2.max_timestamp
WHERE
t1.item_id = 1
GROUP BY t1.item_id;
item_id | color | size | weight
1 | purple | large | 69
Demo

Using MAX date to JOIN tables and get column value

I am trying to get the tracking number from a customers most recent order, but I am having trouble using MAX.
This just keeps returning nothing, even though I know table2 has values in there with dates. What's wrong with my query?
SELECT
t1.Invoice_Num,
t1.Tracking_Num
FROM
table1 t1
JOIN
table2 t2a on t1.Invoice_Num = t2a.Invoice_Num
JOIN (
SELECT
t2b.Invoice_Num,
MAX(t2b.Invoice_Date) Last_Sale
FROM
table2 t2b
WHERE
t2b.Customer_Num = 'cust1'
GROUP BY t2b.Invoice_Num
) LS
on t1.Invoice_Num = LS.Invoice_Num
--------------------------------------------------
Table1
+-------------+--------------+
| Invoice_Num | Tracking_Num |
+-------------+--------------+
| abc123 | 12345678 |
| def456 | 87654321 |
+-------------+--------------+
Table2
+-------------+--------------+--------------+
| Invoice_Num | Customer_Num | Invoice_Date |
+-------------+--------------+--------------+
| abc123 | cust1 | 10/25/2017 |
| def456 | cust1 | 10/24/2017 |
+-------------+--------------+--------------+
Desired output is -
+-------------+--------------+
| Invoice_Num | Tracking_Num |
+-------------+--------------+
| abc123 | 12345678 |
+-------------+--------------+
based on the most recent Invoice_Date of cust1
Here's a generic alternative approach that can come in handy:
use ORDER BY .. DESC and LIMIT 1:
SELECT
t1.Invoice_Num,
t1.Tracking_Num
FROM table1 t1
JOIN table2 t2 USING(Invoice_Num)
WHERE t2.Customer_Num = 'cust1'
ORDER BY t2.Invoice_Date DESC
LIMIT 1
SQL Fiddle
SQL DEMO
SELECT
t1.Invoice_Num,
t1.Tracking_Num
FROM table1 t1
JOIN table2 t2
ON t1.Invoice_Num = t2.Invoice_Num
JOIN ( SELECT MAX(t2b.Invoice_Date) Last_Sale
FROM table2 t2b
WHERE t2b.Customer_Num = 'cust1'
) LS
ON t2.Invoice_Date = LS.Last_Sale
Be carefull because if multiple rows share the Last Sale you will get multiple rows.

MYSQL: Return all rows in one table along with the sum of matching rows in another

EDIT - I apologize but I didn't include the correct information the first time!
I have the following two tables:
table 1
+----+-------+-------+
| id | model | color |
+----+-------+-------+
| 1 | 111AA | red |
| 2 | 222BB | blue |
| 3 | 333CC | |
| 4 | 444DD | green |
+----+-------+-------+
table 2
+----+-------+-------+
| id | model | quant |
+----+-------+-------+
| 6 | 111AA | 2 |
| 7 | 222BB | 5 |
| 8 | 222BB | 3 |
+----+-------+-------+
I need a query that will take all the rows from table 1 where the color column is not empty along with the sum of the column quantity in table two that match a certain model (in the example given, model = '222BB') to produce the following table:
+----+-------+-------+------+
| id | model | color | quant|
+----+-------+-------+------+
| 1 | 111AA | red | |
| 2 | 222BB | blue | 8 |
| 4 | 444DD | green | |
+----+-------+-------+------+
This is what I tried so far:
SELECT t1.id, t1.model, t1.color, SUM(t2.quant)
FROM table1 t1 LEFT OUTER JOIN table2 t2
ON t1.id = t2.id
WHERE t1.color != '' AND t2.model = '222BB'
However, this didn't work.
Any help is greatly appreciated.
Thanks!
To receive the expected table, run the following SQL query:
SELECT t1.id, t1.model, t1.color, IF(t2.model = '222BB', SUM(t2.quant), NULL)
FROM table1 t1
LEFT JOIN table2 t2 ON t1.model = t2.model
WHERE t1.color != ''
GROUP BY t1.model
The result will be the same as in your table. But I think it would be better to update the design to make join on ID column but not model-name.
Try this,
select t1.id, t1.model,t1.color,sum(t2.quant)
from table1 t1
left outer join table2 t2 on (t1.model = t2.model and t1.color <> ‘’)
group by t1.model
In Sql, you should not write != or == with null. It is highly suggested that you use IS NULL and IS NOT NULL clause.
http://www.tutorialspoint.com/sql/sql-null-values.htm
** select a.model,b.total from (select model from table1 where color is not null) a, (select model,sum(quant) total from table2 group by model) b where a.model=b.model;
**

Sql return one row from right table every left table result

My question is how do I get 1 result from each result from Table1 for Table2? And not al results also from table2? I already searches stack overflow I found how to solve this with a id but I want to know how to do this with a Varchar column.
Table1
+--------------+-------------+
| Ip (Varchar) | Count (Int) |
+--------------+-------------+
| 1.1.1.1 | 9 |
| 1.1.1.2 | 6 |
| 1.1.1.3 | 1 |
+--------------+-------------+
Table2
+-------------+--------------+
| Name (Text) | Ip (Varchar) |
+-------------+--------------+
| User01 | 1.1.1.1 |
| User034 | 1.1.1.1 |
| User012 | 1.1.1.1 |
| User21 | 1.1.1.2 |
| User24 | 1.1.1.2 |
| User3 | 1.1.1.3 |
+-------------+--------------+
Wanted result
+--------+---------+-------+
| Name | Ip | Count |
+--------+---------+-------+
| User01 | 1.1.1.1 | 9 |
| User21 | 1.1.1.2 | 6 |
| User3 | 1.1.1.3 | 1 |
+--------+---------+-------+
It does not matter what name will be returned.
Because you just need a random name, you can use group by since you're using mysql:
select t1.ip, t1.count, t2.name
from table1 t1
join table2 t2 on t1.ip = t2.ip
group by t1.ip
Depending on your data, you may need an outer join as well.
SQL Fiddle Demo
You should start by joining the two tables together on the condition that the ip address matches:
SELECT t2.name, t2.ip, t1.count
FROM firstTable t1
JOIN secondTable t2 ON t1.ip = t2.ip;
However, this will return all rows in the second table with a matching ip, so results will appear more than once. If you only want to see specific pairings, you should group by the ip column:
SELECT t2.name, t2.ip, t1.count
FROM firstTable t1
JOIN secondTable t2 ON t2.ip = t1.ip
GROUP BY ip;
As far as the name goes, if you're not picky you can leave it as above and it will be picked arbitrarily, or you could chose something consistent like the minimum username:
SELECT MIN(t2.name), t2.ip, t1.count
FROM firstTable t1
JOIN secondTable t2 ON t2.ip = t1.ip
GROUP BY ip;
Here is an SQL Fiddle example. It shows all three queries so you can visualize the steps I took.