MySQL In result are NULL's when join left 3 tables - mysql

I have problem with result when join 3 tables because I have in some place NULL a should be number or empty cell.
My tables in database:
Table nr 1: rysunek
id_rys | nazwa_rys | nazwa_klienta | ...
3 |01_116230_C0 |PHILIPS
7 |11_002177_A0 |P&G
20 |01_101854_B0 |MARS FOOD
333 |None |None
( + 7 columns which do not use in this query)
Table nr 2: artykul
id_art |id_rys |nazwa_art | id_status | ...
1 |3 |00_16_1234 | 1
2 |7 |00_16_1235 | 3
3 |7 |00_16_1236 | 0
4 |333 |00_16_1237 | 0
( + 10 columns which do not use in this query)
Table nr 3: statusy
id_status |kod_status
1 |IA
2 |NC
3 |861
Mysql query looks like this:
SELECT r.nazwa_klienta
, r.nazwa_rys
, a.nazwa_art
, s.kod_status
FROM artykul a
LEFT
JOIN rysunek r
ON a.id_rys = r.id_rys
LEFT
JOIN statusy s
ON a.id_status = s.id_status;
And result looks like this:
nazwa_klienta | nazwa_rys | nazwa_art | kod_status
NULL | NULL | 00_16_1234 | IA
NULL | NULL | 00_16_1235 | 861
P&G | 11_002177_A0 | 00_16_1236 | NULL
None | None | 00_16_1237 | NULL
I need to the result of query above look like this:
nazwa_klienta | nazwa_rys | nazwa_art | kod_status
PHILIPS | 01_116230_C0 | 00_16_1234 | IA
P&G | 11_002177_A0 | 00_16_1235 | 861
P&G | 11_002177_A0 | 00_16_1236 | [empty cell]
None | None | 00_16_1237 | [empty cell]
How should looks like my query? I tried all join methods but none of them work.
Maybe I should change structure of my tables? I'm waiting for some suggestion from somebody... :)

Left joins are going to create empty entries for your rysunek columns whenever there is no row in that table that matches artykul's. If you don't want them listed, then don't use an outer join between those two tables (I note you didn't list them in your desired output).
For the other NULLs, from kod_status, since it is a numeric column, pretty much your choices are: take the null; or turn it into a 0 with a COALESCE(kod_status,0), or cast the result to a string and turn its nulls into empty strings. There are command-line options in the mysql command-line tool (which your output appears to be from) (see http://dev.mysql.com/doc/refman/5.7/en/mysql-commands.html ) there may be a way to change how it outputs nulls if that would fit your use-model needs.

Related

Optimizing a conditional join in MySQL that depends on the character length of the source table

I'm using MySQL 5.7 and I'm trying to do a join with one of my source tables to a reference table in order to get the appropriate corresponding values. However, I'd like the join to be conditional so it can match according to the length of the value found in the source column.
Source Table
|---------------------|------------------|
| Company_Name | NAICS_Code |
|---------------------|------------------|
| Chem Inc | 325 |
|---------------------|------------------|
| Joe's Farming | 1112 |
|---------------------|------------------|
Reference Table
|---------------------|------------------|--------------------|------------------|
| NAICS_Code_3_Digit | NAICS_Code_ | NAICS_Code_4_Digit | NAICS_Cod_ |
| | 3D_Description | | 4D_Description |
|---------------------|------------------|--------------------|------------------|
| 325 | Chemicals | 3252 | Resin and Rubber|
|---------------------|------------------|--------------------|------------------|
| 111 | Crop Production | 1112 | Fruit and Nuts |
|---------------------|------------------|----------------------------------------
Final Table
|---------------------|------------------|------------------|--------------------|
| Company_Name | NAICS_Code | NAICS_Code_3D_ | NAICS_Code_4D |
| | | Description | Description |
|---------------------|------------------|---------------------------------------|
| Chem Inc | 325 | Chemicals | NULL |
|---------------------|------------------|------------------|--------------------|
| Joe's Farming | 1112 | Crop Production | Fruit and Nuts |
|---------------------|------------------|------------------|--------------------|
While I'm able to write a query that works, it takes an extremely long time and I' curious as to if there is a better way. Here's what I got so far:
SELECT src.Company_Name,
src.NAICS_Code,
CASE
WHEN LENGTH(src.NAICS_Code < 3 THEN NULL
ELSE ref.NAICS_Code_3D_Description
END AS NAICS_Code_3D_Description,
CASE
WHEN LENGTH(src.NAICS_Code < 4 THEN NULL
ELSE ref.NAICS_Code_4D Description
END AS NAICS_Code_4D_Description
FROM source_table AS src
LEFT JOIN reference_table AS ref ON CASE
WHEN LENGTH(src.NAICS_Code) = 4
AND src.NAICS_Code = ref.NAICS_Code_4_Digit THEN 1
WHEN LENGTH(src.NAICS_Code) = 3
AND src.NAICS_Code = ref.NAICS_Code_3_Digit THEN 1
ELSE 0
END = 1;
It might be more efficient to left join twice:
this avoids the need for the complicated logic in the on clause of the join
conditions are exclusive so it will not generate duplicates in the resultset
then you can use coalesce() in the select clause
So:
select
s.compay_name,
s.naics_code,
coalesce(r1.naics_code_3d_description, r2.naics_code_3d_description) naics_code_3d_description,
r2.naics_code_4d_description
from source_table s
left join reference_table r1 on r1.naics_code_3_digit = s.naics_code
left join reference_table r2 on r2.naics_code_4_digit = s.naics_code
If you want to evict source rows that did not match in the reference table, you can add a where clause, like:
where r1.naics_code_3_digit is not null or r2.naics_code_3d_description is not null

Mysql: how to return value or empty string from column ids in table (multi table)

I'M trying to extract all information into my table, but I need to change id, when available, to the name into another table.
I have 1 table like that:
|------------------------------|
|-id-|-systems-|-remote-|-deco-|
| 1 | NULL | 3 | |
| 2 | 21 | NULL | 2 |
|-------------------------------
each column like "systems" / "remote" / "deco" refer to an id into another table
I know how to use INNER JOIN. But if I use that, I got an empty result because the value need to be appears into the others tables.
ex.:
SELECT qd.id,s.name as systems,r.name as remote, d.name as deco
FROM `quote_data` qd
INNER JOIN systems s ON qd.systems=s.id
INNER JOIN remote r ON qd.remote=r.id
INNER JOIN deco d ON qd.deco=d.id
I got empty result.
In the best words, I need to do something like:
|------------------------------|
|-id-|-systems-|-remote-|-deco-|
| 1 | | R42 | |
| 2 | GTV | | B21 |
|-------------------------------
Also, I use innoDB table
Any Idea how to fix that?

MySQL: optimize query for scoring calculation

I have a data table that I use to do some calculations. The resulting data set after calculations looks like:
+------------+-----------+------+----------+
| id_process | id_region | type | result |
+------------+-----------+------+----------+
| 1 | 4 | 1 | 65.2174 |
| 1 | 5 | 1 | 78.7419 |
| 1 | 6 | 1 | 95.2308 |
| 1 | 4 | 1 | 25.0000 |
| 1 | 7 | 1 | 100.0000 |
+------------+-----------+------+----------+
By other hand I have other table that contains a set of ranges that are used to classify the calculations results. The range tables looks like:
+----------+--------------+---------+
| id_level | start | end | status |
+----------+--------------+---------+
| 1 | 0 | 75 | Danger |
| 2 | 76 | 90 | Alert |
| 3 | 91 | 100 | Good |
+----------+--------------+---------+
I need to do a query that add the corresponding 'status' column to each value when do calculations. Currently, I can do that adding the following field to calculation query:
select
...,
...,
[math formula] as result,
(select status
from ranges r
where result between r.start and r.end) status
from ...
where ...
It works ok. But when I have a lot of rows (more than 200K), calculation query become slow.
My question is: there is some way to find that 'status' value without do that subquery?
Some one have worked on something similar before?
Thanks
Yes, you are looking for a subquery and join:
select s.*, r.status
from (select s.*
from <your query here>
) s left outer join
ranges r
on s.result between r.start and r.end
Explicit joins often optimize better than nested select. In this case, though, the ranges table seems pretty small, so this may not be the performance issue.

Combining a LEFT JOIN with GROUP BY, whilst also including NULLs

I'm having trouble combining tables that have a one-to-many mapping using LEFT JOIN and GROUP BY.
I have the following table with a unique ID (in the illustrative example this is house_number)
Houses:
|house_number| bedrooms|
|0 | 4 |
|1 | 3 |
|2 | 1 |
And I want to LEFT JOIN with a second table USING the unique ID, where the second table may or may not have multiple entries per unique ID. E.g,
Occupants:
| house_number | occupant_id | type |
| 0 | 3 | 19 |
| 0 | 1 | 20 |
| 0 | 2 | 21 |
| 2 | 7 | 20 |
Now what I want to achieve is exactly ONE entry per house number, but giving a preference in the LEFT JOIN to occupants with a type of 20, whilst also keeping those houses which do not have any occupants listed, e.g,
|house_number| bedrooms| occupant_id | type |
|0 | 4 | 1 | 20 |
|1 | 3 | null | null |
|2 | 1 | 7 | 20 |
I can use a GROUP BY to achieve only one entry per house, however, I need to ensure that the occupant row returned with it (if it exists) has type = 20.
If I simply use a WHERE (type = 20), then I wouldn't get an entry returned for house_number = 1.
How would I achieve this final table?
What about trying WHERE (type = 20 OR type is null) condition instead?
SELECT h.house_number,h.bedrooms
, o.occupant_id,o.ztype
FROM houses h
LEFT JOIN occupants o ON h.house_number = o.house_number
AND o.ztype =20
;
BTW I had to replace "type" by "ztype" because type is a reserved word in Postgres.

Joining from another table multiple times in a MySQL query

I am trying to do multiple joins on the same MySQL table, but am not getting the results that I expect to get. Hopefully someone can point out my mistake(s).
Table 1 - cpe Table
|id | name
|----------
| 1 | cat
| 2 | dog
| 3 | mouse
| 4 | snake
-----------
Table 2 - AutoSelect
|id | name | cpe1_id | cpe2_id | cpe3_id |
|-----------------------------------------------
| 1 | user1 | 1 | 3 | 4 |
| 2 | user2 | 3 | 1 | 2 |
| 3 | user3 | 3 | 3 | 2 |
| 4 | user4 | 4 | 2 | 1 |
------------------------------------------------
I would like to see an output of
user1 | cat | mouse | snake |
user2 | mouse | snake | dog |
..etc
Here is what I have tried
SELECT * FROM AutoSelect
LEFT JOIN cpe ON
( cpe.id = AutoSelect.cpe1_id ) AND
( cpe.id = AutoSelect.cpe2_id ) AND
( cpe.id = AutoSelect.cpe3_id )
I get blank results. I thought i knew how to do these joins, but apparently when I'm trying to match cpe?_id with the name of the cpe table.
Thanks in advance for any assistance.
You need left join 3 times as well. Currently your query only joins 1 time with 3 critieria as to the join. This should do:
SELECT a.name, cpe1.name, cpe2.name, cpe3.name FROM AutoSelect as a
LEFT JOIN cpe as cpe1 ON ( cpe1.id = a.cpe1_id )
LEFT JOIN cpe as cpe2 ON ( cpe2.id = a.cpe2_id )
LEFT JOIN cpe as cpe3 ON ( cpe3.id = a.cpe3_id )
And you probably mean to INNER JOIN rather than LEFT JOIN unless NULL values are allowed in your AutoSelect table.
I think your design is wrong.
With tables like that, you get it the way it's meant to be in relational databases :
table 1 : animal
id name
1 cat
2 dog
3 mouse
4 snake
table 2 : user
|id | name |
|--------------
| 1 | user1 |
| 2 | user2 |
| 3 | user3 |
| 4 | user4 |
table 3 : association
|id_user | id_animal|
|--------------------
| 1 | 1 |
| 1 | 3 |
| 1 | 4 |
| 2 | 3 |
| 2 | 1 |
| 2 | 2 |
| 3 | 3 |
| 3 | 2
| 4 | 4 |
| 4 | 2 |
| 4 | 1 |
---------------------
Then :
select u.name, a.name from user u, animal a, association ass where ass.user_id = u.id and ass.animal_id = a.id;
In this case, your solution won't produce a good dynamic database. There are other ways to make combinations of multiple tables. I can show you by my own database what you should use and when you should use this solution. The scheme is in dutch, but you'll probably understand the keywords.
Like you, I had to combine my windmills with a kWh-meter, which has to measure the energyproduction of my windmills. What you should do, is this case, is making another table(in my case molenkWhlink). Make sure your tables are INNODB-types(for making Foreign keys). What I've done is combining my meters and mills by putting a pointer(a foreign key) of their ID(in Dutch Volgnummer) in the new table. An advantage you may not need, but I certainly did, is the fact I was able to extend the extra table with connection and disconnection info like Timestamps and metervalues when linking or unlinking. This makes your database way more dynamic.
In my case, I Also had a table for meassurements(metingoverzicht). As you can see in the scheme, I've got 2 lines going from Metingoverzicht to molenkwhlink. The reason for this is quite simple. All meassurements I take, will be saved in table Metingoverzicht. Daily meassurements(which are scheduled) will have a special boolean put on, but unscheduled meassurements, will also me saved here, with the bollean turned off. When switching meters, I need the endvalue from the leaving meter and the startvalue from the new meter, to calculate the value of todays eneryproduction. This is where your solution comes in and an extra table won't work. Usually, when you need just one value from another table a JOIN will be used. The problem in this case is, I've got 2 meassurementIDs in 1 link(1 for connecting and 1 for disconnecting). They both point to the same tablecolumn, because they both need to hold the same type of information. That is when you can use a double JOIN from one table towards the other. Because, both values will only be used once, and just needed to be saved in a different place to avoid having 1 action stored on different locations, which should always be avoided.
http://s1101.photobucket.com/user/Manuel_Barcelona/media/schemedatabase.jpg.html