How to do multiple left joins in SQL Server SQL Query - sql

I'm trying to perform the query below on SQL Server:
SELECT
[dbo].[Machine].[MachineID],
[dbo].[Machine].[CompanyID],
[dbo].[Company].[AccountRef],
[dbo].[Machine].[ProductTypeID],
[dbo].[Machine].[SerialNo],
[dbo].[Machine].[InstallationDate],
[dbo].[Machine].[SalesTypeID],
[dbo].[SalesType].[SalesType],
[dbo].[Machine].[LeasingCompanyID],
[dbo].[LeasingCompany].[Name],
[dbo].[Machine].[QuarterlyRentalCost],
[dbo].[Machine].[Term],
[dbo].[Machine].[ExpiryDate],
[dbo].[Machine].[Scales],
[dbo].[Machine].[Chips],
[dbo].[Machine].[ContractTypeID],
[dbo].[ContractType].[ContractType],
[dbo].[Machine].[ContractCost],
[dbo].[Machine].[InvoiceDate],
[dbo].[Machine].[ServiceDueDate],
[dbo].[Machine].[ServiceNotes],
[dbo].[Machine].[modelID],
[dbo].[Machine].[Model],
[dbo].[Machine].[IMP_Machine Reference],
[dbo].[Machine].[Smart]
FROM
[dbo].[Machine], [dbo].[Company], [dbo].[SalesType], [dbo].[LeasingCompany], [dbo].[ContractType]
LEFT JOIN
[dbo].[Machine] as A ON A.[CompanyID] = [dbo].[Company].[CompanyID]
LEFT JOIN
[dbo].[Machine] as B ON B.[SalesTypeID] = [dbo].[SalesType].[SalesTypeID]
LEFT JOIN
[dbo].[Machine] as C ON C.[LeasingCompanyID] = [dbo].[LeasingCompany].[LeasingCompanyID]
LEFT JOIN
[dbo].[Machine] as D ON D.[ContractTypeID] = [dbo].[ContractType].[ContractTypeID] ;
But for some reason that i cannot see for the life of me, the destination column name in the bottom 3 join statements is reporting "The multi part identifier could not be bound".
Could anyone assist please?
Many Thanks,

You were pretty close, for readability, you dont need the extensive [dbo].[table] all over. You can define it once in the from clause with an alias, then use that alias the rest of the way through. Also, make the alias make sense to the context of the table as you will see in this below. LeasingCompany lc, SalesType st, etc.
Also, I try to have indented so I always know the first table of the join relationship and the JOIN indented on where it is being joined to. Then I keep the orientation of the from/to table aliases the same context.
Since the machine table is used once and joined to 4 different lookup tables, you can reuse the same "m" alias to each underlying. Think of a tree and branches. The root tree is your "Machine", and all the branches are the lookups.
SELECT
m.MachineID,
m.CompanyID,
c.AccountRef,
m.ProductTypeID,
m.SerialNo,
m.InstallationDate,
m.SalesTypeID,
st.SalesType,
m.LeasingCompanyID,
lc.LeasingCompany.Name,
m.QuarterlyRentalCost,
m.Term,
m.ExpiryDate,
m.Scales,
m.Chips,
m.ContractTypeID,
ct.ContractType,
m.ContractCost,
m.InvoiceDate,
m.ServiceDueDate,
m.ServiceNotes,
m.modelID,
m.Model,
m.IMP_Machine Reference,
m.Smart
FROM
Machine m
LEFT JOIN Company c
ON m.CompanyID = c.CompanyID
LEFT JOIN SalesType st
ON m.SalesTypeID = st.SalesTypeID
LEFT JOIN LeasingCompany lc
ON m.LeasingCompanyID = lc.LeasingCompanyID
LEFT JOIN ContractType ct
ON m.ContractTypeID = ct.ContractTypeID ;

Related

Nesting multiple same select queries and reuse without second round trip to database

I am having a rows with two different IDs in database. Now I am trying to show two different data columns in one row, I tried something like this:
SELECT
[dbo].[fnHexToNumber]([Participant].[Stake]) AS [PlayerStake],
(SELECT [dbo].[fnHexToNumber]([Stake])
FROM [dbo].[Participant_Complete]
WHERE [ParticipantId] = [Fold].[HouseParticipantId]) AS [HouseStake],
([dbo].[fnHexToNumber]([Participant].[Stake]) + [dbo].[fnHexToNumber]([C].[RunningWinLoss])) AS [PlayerStakeAfterRound],
(SELECT [dbo].[fnHexToNumber]([Stake])
FROM [dbo].[Participant_Complete]
WHERE [ParticipantId] = [Fold].[HouseParticipantId]) - [dbo].[fnHexToNumber]([C].[RunningWinLoss]) AS [HouseStakeAfterRound]
FROM
[dbo].[Round_Complete] AS [C]
INNER JOIN
[dbo].[Fold_Complete] AS [Fold] ON [Fold].[Id] = [C].[Id]
INNER JOIN
[dbo].[Participant_Complete] AS [Participant] ON [Participant].[ParticipantId] = [Fold].[PlayerParticipantId]
This works, but as you can see it will do two trips to database for same nested select. How can I make this only one round trip?
You are referring to the subqueries. That is not a "round trip to the database", which usually refers to an application calling a query.
All the square braces make the query hard to read, but you can fix this using apply:
SELECT [dbo].[fnHexToNumber](p.[Stake]) AS PlayerStake,
h.HouseStake,
([dbo].[fnHexToNumber](p.[Stake]) + [dbo].[fnHexToNumber]([C].RunningWinLoss)) AS PlayerStakeAfterRound,
(h.HouseStake - [dbo].fnHexToNumber(C.RunningWinLoss)) AS HouseStakeAfterRound
FROM [dbo].[Round_Complete] c JOIN
[dbo].[Fold_Complete] f
ON f.[Id] = c.[Id] JOIN
[dbo].[Participant_Complete] pc
ON px.[ParticipantId] = f.[PlayerParticipantId] OUTER APPLY
(SELECT [dbo].[fnHexToNumber]([Stake]) as HouseStake
FROM [dbo].[Participant_Complete] pch
WHERE pch.ParticipantId = f.HouseParticipantId
) h
Just join the same table a second time instead of pulling the data as sub-queries.
Also, you only need brackets around names if the names contain a space (which is bad practice in general). If the names don't have a space, the brackets are totally extraneous.
SELECT
dbo.fnHexToNumber(Participant.Stake) AS PlayerStake,
dbo.fnHexToNumber(p.Stake) as HouseStake,
(dbo.fnHexToNumber(Participant.Stake) + dbo.fnHexToNumber(C.RunningWinLoss)) AS PlayerStakeAfterRound,
dbo.fnHexToNumber(p.Stake) - dbo.fnHexToNumber(c.RunningWinLoss) as HouseStakeAfterRound
FROM dbo.Round_Complete AS C
INNER JOIN dbo.Fold_Complete AS Fold
ON Fold.Id = C.Id
INNER JOIN dbo.Participant_Complete AS Participant
ON Participant.ParticipantId = Fold.PlayerParticipantId
INNER JOIN dbo.Participant_Complete AS p
ON p.ParticipantId = Fold.HouseParticipantId

MS Access INNER JOIN/LEFT JOIN problems

I have the following SQL string which tries to combine an INNER JOIN with a LEFT JOIN in the FROM section.
As you can see I use table VIP_APP_VIP_SCENARIO_DETAIL_LE to perform the query. When I use it against this table, Access give me an "Invalid Operation" error.
Interestingly, when I use the EXACT same query using the VIP_APP_VIP_SCENARIO_DETAIL_BUDGET or VIP_APP_VIP_SCENARIO_DETAIL_ACTUALS table, it performs flawlessly.
So why would it work on two tables but not the other? All fields are in all tables and the data types are correct.
As a side note: on the query with the error, if I change the LEFT JOIN to an INNER JOIN, it runs with no problem! I really need a LEFT JOIN though.
SELECT
D.MATERIAL_NUMBER,
D.MATERIAL_DESCRIPTION,
D.PRODUCTION_LOT_SIZE,
D.STANDARDS_NAME,
D.WORK_CENTER,
S.OP_SHORT_TEXT,
S.OPERATION_CODE,
D.LINE_SPEED_UPM,
D.PERCENT_STD,
D.EQUIPMENT_SU,
D.EQUIPMENT_CU,
D.OPERATOR_NUM,
V.COSTING_LOT_SIZE,
V.VOL_TOTAL_ADJ
FROM
([STDS_SCENARIO: TEST] AS D INNER JOIN MASTER_SUMMARY AS S ON
D.MATERIAL_NUMBER = S.MATERIAL_NUMBER AND D.WORK_CENTER = S.WORK_CENTER)
LEFT JOIN
(SELECT ITEM_CODE, COSTING_LOT_SIZE, VOL_TOTAL_ADJ
FROM
VIP_APP_VIP_SCENARIO_DETAIL_LE
WHERE SCENARIO_ID = 16968) AS V ON D.MATERIAL_NUMBER = V.ITEM_CODE
ORDER BY D.MATERIAL_NUMBER, D.STANDARDS_NAME, S.OPERATION_CODE;
tried to mock this up in SQL server with some tables of my own, but the structure seemed to work, this follows the pattern referenced above. (hopefully no syntax errors left here)
SELECT * FROM (
select
D.MATERIAL_NUMBER,
D.MATERIAL_DESCRIPTION,
D.PRODUCTION_LOT_SIZE,
D.STANDARDS_NAME,
D.WORK_CENTER,
S.OP_SHORT_TEXT,
S.OPERATION_CODE,
D.LINE_SPEED_UPM,
D.PERCENT_STD,
D.EQUIPMENT_SU,
D.EQUIPMENT_CU,
D.OPERATOR_NUM
FROM [STDS_SCENARIO: TEST] D
INNER JOIN MASTER_SUMMARY S
ON D.MATERIAL_NUMBER = S.MATERIAL_NUMBER AND D.WORK_CENTER = S.WORK_CENTER) AS J
LEFT JOIN
(SELECT ITEM_CODE, COSTING_LOT_SIZE, VOL_TOTAL_ADJ
FROM
VIP_APP_VIP_SCENARIO_DETAIL_LE
WHERE SCENARIO_ID = 16968) AS V ON J.MATERIAL_NUMBER = V.ITEM_CODE
ORDER BY J.MATERIAL_NUMBER, J.STANDARDS_NAME, J.OPERATION_CODE;
Had help from a friend and we discovered that it was a casting problem between a linked Oracle table and the Access table. To fix the problem we casted both sides of the linked fields to a string:
CSTR(D.[MATERIAL_NUMBER]) = CSTR(V.[ITEM_CODE])

Changing old join to new join

I am new to SQL so any help is greatly appreciated. I have a query that seems to be working that has old style joins, and I need to change it to new style joins. the current query is like:
SELECT
STAR.V_DISASTER_DIMENSIONS .DISASTER_NUMBER,
STAR.PA_PROJECT_DIMENSIONS .PW_NUMBER,
STAR.PA_PROJECT_SITE_DIMENSIONS.SITE_NUMBER,
STAR.PA_PROJECT_FACTS .PROJECT_AMOUNT,
STAR.PA_MITIGATION_DIMENSIONS .MITIGATION_ACTIVITY_STATUS
FROM
STAR.V_DISASTER_DIMENSIONS,
STAR.PA_PROJECT_DIMENSIONS,
STAR.PA_PROJECT_SITE_DIMENSIONS,
STAR.PA_MITIGATION_DIMENSIONS,
STAR.PA_PROJECT_FACTS,
STAR.PA_PROJECT_SITE_FACTS
WHERE
( STAR.PA_PROJECT_DIMENSIONS.PA_PROJECT_ID = STAR.PA_PROJECT_FACTS.PA_PROJECT_ID )
AND
( STAR.PA_PROJECT_FACTS.DISASTER_ID = STAR.V_DISASTER_DIMENSIONS.DISASTER_ID )
AND
( STAR.PA_MITIGATION_DIMENSIONS.PA_MITIGATION_ID = STAR.PA_PROJECT_FACTS.PA_PROJECT_ID )
AND
( STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_ID = STAR.PA_MITIGATION_DIMENSIONS.PA_MITIGATION_ID )
AND
( STAR.PA_PROJECT_SITE_FACTS.DISASTER_ID = STAR.V_DISASTER_DIMENSIONS.DISASTER_ID )
AND
( STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_ID = STAR.PA_PROJECT_DIMENSIONS.PA_PROJECT_ID )
AND
( STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_SITE_ID = STAR.PA_PROJECT_SITE_DIMENSIONS.PA_PROJECT_SITE_ID )
My attempt to convert is below. I don't know where to put the extra conditions because they are not 1 to 1 with tables.
FROM
STAR.V_DISASTER_DIMENSIONS
JOIN STAR.PA_PROJECT_SITE_FACTS ON STAR.PA_PROJECT_SITE_FACTS.DISASTER_ID = STAR.V_DISASTER_DIMENSIONS.DISASTER_ID
JOIN STAR.PA_PROJECT_DIMENSIONS ON STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_ID = STAR.PA_PROJECT_DIMENSIONS.PA_PROJECT_ID
JOIN STAR.PA_PROJECT_SITE_DIMENSIONS ON STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_SITE_ID = STAR.PA_PROJECT_SITE_DIMENSIONS.PA_PROJECT_SITE_ID
JOIN STAR.PA_MITIGATION_DIMENSIONS ON STAR.PA_PROJECT_SITE_FACTS.PA_PROJECT_ID = STAR.PA_MITIGATION_DIMENSIONS.PA_MITIGATION_ID
JOIN STAR.PA_PROJECT_FACTS ON (
STAR.PA_PROJECT_FACTS .DISASTER_ID = STAR.V_DISASTER_DIMENSIONS.DISASTER_ID AND
STAR.PA_MITIGATION_DIMENSIONS.PA_MITIGATION_ID = STAR.PA_PROJECT_FACTS .PA_PROJECT_ID AND
STAR.PA_PROJECT_DIMENSIONS .PA_PROJECT_ID = STAR.PA_PROJECT_FACTS .PA_PROJECT_ID
)
Change , to INNER JOINs with ON condition:
SELECT
STAR.V_DISASTER_DIMENSIONS.DISASTER_NUMBER,
STAR.PA_PROJECT_DIMENSIONS.PW_NUMBER,
STAR.PA_PROJECT_SITE_DIMENSIONS.SITE_NUMBER,
STAR.PA_PROJECT_FACTS.PROJECT_AMOUNT,
STAR.PA_MITIGATION_DIMENSIONS.MITIGATION_ACTIVITY_STATUS
FROM
STAR.PA_PROJECT_DIMENSIONS PD
INNER JOIN STAR.PA_PROJECT_FACTS PF ON PD.PA_PROJECT_ID=PF.PA_PROJECT_ID
INNER JOIN STAR.V_DISASTER_DIMENSIONS DD ON DD.DISASTER_ID=PF.DISASTER_ID
INNER JOIN STAR.PA_MITIGATION_DIMENSIONS MD ON MD.PA_MITIGATION_ID=PF.PA_PROJECT_ID
INNER JOIN STAR.PA_PROJECT_SITE_FACTS PSF ON PSF.PA_PROJECT_ID=MD.PA_MITIGATION_ID
AND PSF.DISASTER_ID=DD.DISASTER_ID
AND PSF.PA_PROJECT_ID=PD.PA_PROJECT_ID
INNER JOIN STAR.PA_PROJECT_SITE_DIMENSIONS PSD ON PSD.PA_PROJECT_SITE_ID=PSF.PA_PROJECT_SITE_ID
Select * from
a,b
where a.z = b.y
would be written as
Select * from
a
INNER JOIN
b
ON a.z = b.y
It is easy. Just start with the facts table and join related tables on foreign key = key.
First of all you should use table aliases to get the query more readable. Also use some lowercase letters, too.
Then just write the table names (or the aliases) on paper and draw a line for each condition from one table to the other. Then pick one table to start with, e.g. pa_project_site_dimensions which is only linked to one table.
SELECT
dd.disaster_number,
pd.pw_number,
psd.site_number,
psf.project_amount,
md.mitigation_activity_status
FROM star.pa_project_site_dimensions psd
JOIN star.pa_project_site_facts psf ON psf.pa_project_site_id = psd.pa_project_site_id
JOIN star.v_disaster_dimensions dd ON dd.disaster_id = psf.disaster_id
JOIN star.pa_mitigation_dimensions md ON md.pa_mitigation_id = psf.pa_project_id
JOIN star.pa_project_dimensions pd ON pd.pa_project_id = psf.pa_project_id
JOIN star.pa_project_facts pf ON pf.disaster_id = dd.disaster_id
AND pf.pa_project_id = md.pa_mitigation_id
AND pf.pa_project_id = pd.pa_project_id
;
However, this is a strange query. First of all there is no limiting condition, you simply join all records, rather than retrieving data for, say, one particular project.
Moreover, you deal with several dimensions. Obviously a project has facts (pa_project_facts) and dimensions (pa_project_dimensions). With 5 facts and 3 dimensions you'd get 15 rows with all their combinations. Then there are also project sites it seems (maybe a table pa_project_sites we don't see in the query). Either that project site has facts on its own (pa_project_site_facts) that you also combine with all rows, or a project site is linked to a project fact via pa_project_site_facts, but then pa_project_facts wouldn't have to be joined by pa_project_id only, but also by some fact ID.
Also this looks strange: md.pa_mitigation_id = psf.pa_project_id. Is a mitigation the same as a project?
So after all have a look at all columns that need to be joined on. Think about how the tables are related and if you are not building combinations that make no sense.

Ignore null values in select statement

I'm trying to retrieve a list of components via my computer_system, BUT if a computer system's graphics card is set to null (I.e. It has an onboard), the row isn't returned by my select statement.
I've been trying to use COALESCE without results. I've also tried with and OR in my WHERE clause, which then just returns my computer system with all different kinds of graphic cards.
Relevant code:
SELECT
computer_system.cs_id,
computer_system.cs_name,
motherboard.name,
motherboard.price,
cpu.name,
cpu.price,
gfx.name,
gfx.price
FROM
public.computer_case ,
public.computer_system,
public.cpu,
public.gfx,
public.motherboard,
public.ram
WHERE
computer_system.cs_ram = ram.ram_id AND
computer_system.cs_cpu = cpu.cpu_id AND
computer_system.cs_mb = motherboard.mb_id AND
computer_system.cs_case = computer_case.case_id AND
computer_system.cs_gfx = gfx.gfx_id; <-- ( OR computer_system.cs_gfx IS NULL)
Returns:
1;"Computer1";"Fractal Design"; 721.00; "MSI Z87"; 982.00; "Core i7 I7-4770K "; 2147.00; "Crucial Gamer"; 1253.00; "ASUS GTX780";3328.00
Should I use Joins? Is there no easy way to say return the requested row, even if there's a bloody NULL value. Been struggling with this for at least 2 hours.
Tables will be posted if needed.
EDIT: It should return a second row:
2;"Computer2";"Fractal Design"; 721.00; "MSI Z87"; 982.00; "Core i7 I7-4770K "; 2147.00; "Crucial Gamer"; 1253.00; "null/nothing";null/nothing
You want a LEFT OUTER JOIN.
First, clean up your code so you use ANSI joins so it's readable:
SELECT
computer_system.cs_id,
computer_system.cs_name,
motherboard.name,
motherboard.price,
cpu.name,
cpu.price,
gfx.name,
gfx.price
FROM
public.computer_system
INNER JOIN public.computer_case ON computer_system.cs_case = computer_case.case_id
INNER JOIN public.cpu ON computer_system.cs_cpu = cpu.cpu_id
INNER JOIN public.gfx ON computer_system.cs_gfx = gfx.gfx_id
INNER JOIN public.motherboard ON computer_system.cs_mb = motherboard.mb_id
INNER JOIN public.ram ON computer_system.cs_ram = ram.ram_id;
Then change the INNER JOIN on public.gfx to a LEFT OUTER JOIN:
LEFT OUTER JOIN public.gfx ON computer_system.cs_gfx = gfx.gfx_id
See PostgreSQL tutorial - joins.
I very strongly recommend reading an introductory tutorial to SQL - at least the PostgreSQL tutorial, preferably some more material as well.
It looks like it's just a bracket placement issue. Pull the null check and the graphics card id comparison into a clause by itself.
...
computer_system.cs_case = computer_case.case_id AND
(computer_system.cs_gfx IS NULL OR computer_system.cs_gfx = gfx.gfx_id)
Additionally, you ask if you should use joins. You are in fact using joins, by virtue of having multiple tables in your FROM clause and specifying the join criteria in the WHERE clause. Changing this to use the JOIN ON syntax might be a little easier to read:
FROM sometable A
JOIN someothertable B
ON A.somefield = B.somefield
JOIN somethirdtable C
ON A.somefield = C.somefield
etc
Edit:
You also likely want to make the join where you expect the null value to be a left outer join:
SELECT * FROM
first_table a
LEFT OUTER JOIN second_table b
ON a.someValue = b.someValue
If there is no match in the join, the row from the left side will still be returned.

Do I misunderstand joins?

I'm trying to learn the the ansi-92 SQL standard, but I don't seem to understand it completely (I'm new to the ansi-89 standard as well and in databases in general).
In my example, I have three tables kingdom -< family -< species (biology classifications).
There may be kingdoms without species nor families.
There may be families without species nor kindgoms.
There may be species without kingdom or families.
Why this may happen?
Say a biologist, finds a new species but he has not classified this into a kingdom or family, creates a new family that has no species and is not sure about what kingdom it should belong, etc.
here is a fiddle (see the last query): http://sqlfiddle.com/#!4/015d1/3
I want to make a query that retrieves me every kingdom, every species, but not those families that have no species, so I make this.
select *
from reino r
left join (
familia f
right join especie e
on f.fnombre = e.efamilia
and f.freino = e.ereino
) on r.rnombre = f.freino
and r.rnombre = e.ereino;
What I think this would do is:
join family and species as a right join, so it brings every species, but not those families that have no species. So, if a species has not been classified into a family, it will appear with null on family.
Then, join the kingdom with the result as a left join, so it brings every kingdom, even if there are no families or species classified on that kingdom.
Am I wrong? Shouldn't this show me those species that have not been classified? If I do the inner query it brings what I want. Is there a problem where I'm grouping things?
You're right on your description of #1... the issue with your query is on step #2.
When you do a left join from kingdom to (family & species), you're requesting every kingdom, even if there's no matching (family & species)... however, this won't return you any (family & species) combination that doesn't have a matching kingdom.
A closer query would be:
select *
from reino r
full join (
familia f
right join especie e
on f.fnombre = e.efamilia
and f.freino = e.ereino
) on r.rnombre = f.freino
and r.rnombre = e.ereino;
Notice that the left join was replaced with a full join...
however, this only returns families that are associated with a species... it doesn't return any families that are associated with kingdoms but not species.
After re-reading your question, this is actually want you wanted...
EDIT: On further thought, you could re-write your query like so:
select *
from
especie e
left join familia f
on f.fnombre = e.efamilia
and f.freino = e.ereino
full join reino r
on r.rnombre = f.freino
and r.rnombre = e.ereino;
I think this would be preferrable, because you eliminate the RIGHT JOIN, which are usually frowned upon for being poor style... and the parenthesis, which can be tricky for people to parse correctly to determine what the result will be.
In case this helps:
Relationally speaking, [OUTER JOIN is] a kind of shotgun marriage: It
forces tables into a kind of union—yes, I do mean union, not join—even
when the tables in question fail to conform to the usual requirements
for union. It does this, in effect, by padding one or
both of the tables with nulls before doing the union, thereby making
them conform to those usual requirements after all. But there's no
reason why that padding shouldn't be done with proper values instead
of nulls, as in this example:
SELECT SNO , PNO
FROM SP
UNION
SELECT SNO , 'nil' AS PNO
FROM S
WHERE SNO NOT IN ( SELECT SNO FROM SP )
The above is equivalent to:
SELECT SNO , COALESCE ( PNO , 'nil' ) AS PNO
FROM S NATURAL LEFT OUTER JOIN SP
Source:
SQL and Relational Theory: How to Write Accurate SQL Code By C. J. Date
If you want the query rewritten with only the slightest change from what you have, you can change the LEFT join to a FULL join. You can further remove the redundant parenthesis and the r.rnombre = f.freino from the ON condition:
select *
from reino r
full join --- instead of LEFT JOIN
familia f
right join especie e
on f.fnombre = e.efamilia
and f.freino = e.ereino
on r.rnombre = e.ereino;
---removed the: r.rnombre = f.freino
Try to use this:
select *
from reino r
join especie e on (r.rnombre = e.ereino)
join familia f on (f.freino = e.ereino and f.fnombre = e.efamilia)
could it be, that you interchanged efamilia and enombre in table especie?