Struggling with a one to many that also includes the master record without having to add a detail record that references itself?
select * from master m
inner join detail d on d.id2 = m.id
where d.id1 = 1
This will return
2,John,1,2
4,Nancy,1,4
How do I get it to also return
1,Jim,nul,nul
If I add 1,1 record to the below detail it works, but was hoping to get around that.
Master
1,Jim
2,John
3,Fred
4,Nancy
5,Jen
Detail
1,2
1,4
3,5
Thanks
Glenn
I think you want a more complicated on expression:
select *
from master m inner join
detail d
on d.id2 = m.id or d.id1 = m.id
where d.id1 = 1;
You could also write this as:
on m.id in (d.id1, d.id2)
Related
I am interested in the results found in table g, which shares a key, sample_name, with tables s and l. In this question the tables are
s - samples,
p - projects,
l - analyses, and
g, analysis g,
all within schema a.
In the interest of optimization, I only want to look for table g after having confirmed that l.analysis_g is NOT NULL.
Given: The only information that I start out with is the project names. The project table, p is linked with other tables by the samples table s. s is linked to every table. Table l contains types of analysis and each column is either NULL or 1.
In the example below I am trying a case but I realize this may be totally incorrect.
SELECT s.sample_name,
s.project_name,
g.*
FROM a.samples s
JOIN a.analyses l
ON s.sample_name = l.sample_name
JOIN a.analysis_g g
ON s.sample_name = g.sample_name
WHERE s.project_name IN (SELECT p.project_name
FROM a.projects p
WHERE p.project_name_other
IN ('PROJ_1',
'PROJ_2'))
;
Then perhaps in the where clause? It's still really hard to understand what you want . . .
SELECT s.sample_name,
s.project_name,
g.*
FROM a.samples s
JOIN a.analyses l
ON s.sample_name = l.sample_name
JOIN a.analysis_g g
ON s.sample_name = g.sample_name
WHERE s.project_name IN (SELECT p.project_name
FROM a.projects p
WHERE p.project_name_other
IN ('PROJ_1',
'PROJ_2'))
and l.analysis_g IS NOT NULL
;
As a side note, I think you could join p.project_name and avoid the where clause. AND I think you might want some inner joins -- but I'm not sure.
SELECT s.sample_name,
s.project_name,
g.*
FROM a.samples s
JOIN a.analyses l ON s.sample_name = l.sample_name
JOIN a.analysis_g g ON s.sample_name = g.sample_name
JOIN a.projects p ON s.project_name = p.project_name
WHERE p.project_name_other IN ('PROJ_1', 'PROJ_2')
and l.analysis_g IS NOT NULL
Again: Please show an example! We can't help if we have to guess, but I'll give it a try...
If l.analysis_g contains an ID from table g, then you can just use:
SELECT * FROM g
JOIN l on g.id = l.analysis_g
WHERE blah, blah, blah...
I removed your WHERE clause because you haven't provided enough information to allow anyone to help optimize it (if needed).
I'm trying to transpose my results from the following code which is joining multiple tables together. I know i need to use a PIVOT for this and it may be a simple fix, but i'm having huge difficultly getting the code to work. My code is as follows:
SELECT F.SetValue, D.Name FROM Device D
INNER JOIN Location L ON D.LocationId = L.LocationId
INNER JOIN Fitting F ON L.LocationId = F.LocationId
INNER JOIN LocationTypeFitting LTF ON F.LocationTypeFittingId = LTF.LocationTypeFittingId
WHERE D.DeviceName = 'Device 1' AND LTF.Name LIKE '%Television%';
which prints the following results:
SetValue | Name
===========================
1 | TV_Power
1 | TV_Volume
1 | TV_Source
I need to return the values as below:
TV_Power | TV_Volume | TV_Source
================================
1 | 1 | 1
I know i'll also need a GROUP BY statement, but the the joining of additional tables is making this particular query increasingly difficult. Any help would be very much appreciated.
I would do the following two things:
Wrap the whole query in a sub-query and apply the pivot syntax.
Add another column, such as DeviceName from the Device table (or some other table), so that you can differentiate the rows once the pivot has been executed (I assume there will be more than one row).
it also shows where the group by would go in the comments.
select post_pivot.*
from (
SELECT F.SetValue, D.Name, D.DeviceName FROM Device D
INNER JOIN Location L ON D.LocationId = L.LocationId
INNER JOIN Fitting F ON L.LocationId = F.LocationId
INNER JOIN LocationTypeFitting LTF ON F.LocationTypeFittingId = LTF.LocationTypeFittingId
WHERE D.DeviceName = 'Device 1' AND LTF.Name LIKE '%Television%'
--group by (if needed)
) as pre_pivot
pivot (max(pre_pivot.set_value) for pre_pivot.Name in ([TV_Power], [TV_Volume], [TV_Source])) as post_pivot
Hopefully this will be sufficient or will give you enough to go on.
SELECT 'DeviceType' as DeviceTYpe,* FROM
(
SELECT D.Name, F.SetValue FROM Device D
INNER JOIN Location L ON D.LocationId = L.LocationId
INNER JOIN Fitting F ON L.LocationId = F.LocationId
INNER JOIN LocationTypeFitting LTF ON F.LocationTypeFittingId = LTF.LocationTypeFittingId
WHERE D.DeviceName = 'Device 1' AND LTF.Name LIKE '%Television%'
) AS SourceTable
PIVOT
(
MAX(SetValue)
FOR Name in ([TV_Power], [TV_Volume], [TV_Source])
) As PivotTable
I know there ust be a few hundred of this similar post, but I have tried all the other ways in MS Access and still cannot get it to work.
So my working code is as follows
SELECT FVR.*, V.[Week Commencing], F.Date, V.Date
FROM FVR
INNER JOIN (F
INNER JOIN V ON (F.[Week Commencing] = V.[Week Commencing]) AND (F.GUID = V.GUID))
ON (FVR.GUID = V.GUID) AND (FVR.GUID = F.GUID)
My desired effect would be to show the Dates of the "F" table that have no entries in the "V"Table.
Sorry for being crpytic on the tables but it is for work. I thoght i had a good idead on how to do most of this.
any help would be amazing as I have been pulling my hair over this for a while now.
Cheers and thanks in advance.
Editing this to add in the full code as it will make more sense.
I basically have am unable to produce the Data range from F(Forecast) that Does not match in V(Visits) am trying to bring up a list of forecasted dates that have not been visited using the Week Commencing and GUID from both tables, The FVR table is just a table that holds the regional data matching up to the GUID. #Hogan I tried your way and ended up with syntax errors, I almost got somewhere and then lost it again. I thought I had a bit more knowledge of SQL than this.
Full code is as follows
SELECT FVR.*, [Visits].[Week Commencing], [Forecast].[Forecast Date], [Visits].Date
FROM ForecastVisitRegion
INNER JOIN ([Forecast] INNER JOIN [Visits] ON ([Forecast].[Week Commencing] = [Visits].[Week Commencing])
AND ([Forecast].GUID = [Visits].GUID)) ON (FVR.GUID = [Visits].GUID)
AND (FVR.GUID = [External - Forecast].GUID)
Thanks again
Stephen Edwards
You need to use left joins:
SELECT FVR.*, V.[Week Commencing], NZ(V.Date,F.Date) as virtual_date
FROM FVR
LEFT JOIN F ON FVR.GUID = F.GUID
LEFT JOIN V ON FVR.GUID = V.GUID F.[Week Commencing] = V.[Week Commencing]
Not sure I understand why FVR is coming into the mix but you need a left Join.
Select F.*
from F
left join V on F.[Week Commencing] = V.[Week Commencing] AND F.GUID = V.GUID
where V.GUID is null
The left join ensures all the records (matched or not) from F are included in the result set. Then the where V.GUID is null removes the records where no match was found in V leaving you with the F records with no match.
Another approach would be to use the NOT EXISTS statement in the WHERE Clause
Select F.*
from F
where not exists (select * from V where F.[Week Commencing] = V.[Week Commencing] AND F.GUID = V.GUID)
Over simplifying here, but I need help. Let's say I have a SQL statement like this:
SELECT * FROM Policy p
JOIN OtherPolicyFile o on o.PolicyId = p.PolicyId
WHERE OtherPolicyFile.Status IN (9,10)
OK, so here is the story. I need to also pull any OtherPolicyFile where the Status = 11, but ONLY if there is a matching OtherPolicyFile with a status 9 or 10 as well.
In other words, I would not normally pull an OtherPolicyFile with status 11, but if that policy also has an OtherPolicyFile with a status 9 or 10, then I need to also pull any OtherPolicyFiles with a status of 11.
There is probably a really easy way to write this, but I'm frazzled at the moment and it is not coming to me without jumping through hoops. Any help would be appreciated.
Perform one extra left join and test the left joined table for NULL:
SELECT p.*, o.*
FROM Policy p
JOIN OtherPolicyFile o on o.PolicyId = p.PolicyId
LEFT JOIN OtherPolicyFile o9or10
on o9or10.PolicyId = p.PolicyId and o9or10.Status IN (9,10)
WHERE o.Status IN (9,10)
OR o.Status = 11 AND o9or10.PolicyId is NOT NULL
GROUP BY <whatever key you need>
But beware - you need to use GROUP BY so that the added LEFT JOIN doesn't duplicate lines. I cannot propose proper key because I don't know your schema, so fill in appropriate one (possibly the primary ID of OtherPolicyFile? So something like o.ID in your case? But I really don't know)
I would add a subquery to see if 9 or 10 exists. Here's the fiddle: http://sqlfiddle.com/#!3/1a68c/2
SELECT * FROM Policy p
JOIN OtherPolicyFile o on o.PolicyId = p.PolicyId
WHERE o.Status IN (9,10)
OR (o.Status = 11 AND
exists (select * from OtherPolicyFile innerO
where innerO.PolicyId = p.PolicyId
and (innerO.Status = 9 or innerO.Status=10)))
I believe this will give the best possible performance. Note no joins.
it will only execute on sql server 2005+
Be aware that you can't 'select *' and have identical column names in both tables for this to work. So you have to specify which columns you need.
SELECT * from
(
SELECT <your columns>,
statuscheck = min(nullif(o.status, 11)) over (partition by o.PolicyId)
FROM Policy p
JOIN OtherPolicyFile o on o.PolicyId = p.PolicyId
WHERE o.Status IN (9,10,11)
) a
WHERE statuscheck is not null
I've got a SQL related question regarding a general database structure that seems to be somewhat common. I came up with it one day while trying to solve a problem and (later on) I've seen other people do the same thing (or something remarkably similar) so I think the structure itself makes sense. I just have trouble trying to form certain queries against it.
The idea is that you've got a table with "items" in it and you want to store a set of fields and their values for each item. Normally this would be done by simply adding columns to the items table, the problem is that the field(s) themselves (not just the values) vary from item to item. For example, I might have two items:
Article 1
product_id = aproductid
hidden_key = ahiddenkeyvalue
Article 2
product_id = anotherproductid
address = anaddress
You can see that both items have a product_id field (with different values) but the data stored for each item is different.
The structure in the database ends up something like this:
ItemsTable
id
itemdata_1
itemdata_2
...
FieldsTable
id
field_name
...
And the table that relates them and makes it work
FieldsItemRelationsTable
field_id
item_id
value
Well when I'm trying to do something that involves just one "dynamic field" value there's no problem. I usually do something similar to:
SELECT i.* FROM ItemsTable i
INNER JOIN FieldsItemRelationsTable v ON v.item_id = i.id
INNER JOIN FieldsTable f ON f.id = v.field_id
WHERE v.value = 50 AND f.name = 'product_id';
Which selects all items where product_id=50
The problem arises when I need to do something involving multiple "dynamic field" values. Say I want to select all items where product_id = 50 AND hidden_key = 30. Is it possible with a single SQL statement? I've tried:
SELECT i.* FROM ItemsTable i
INNER JOIN FieldsItemRelationsTable v ON v.item_id = i.id
INNER JOIN FieldsTable f ON f.id = v.field_id
WHERE (v.value = 50 AND f.name = 'product_id')
AND (v.value = 30 AND f.name = 'hidden_key');
But it just returns zero rows.
You'll need to do a seperate join for each value you are bringing back...
SELECT i.* FROM ItemsTable i
INNER JOIN FieldsItemRelationsTable v ON v.item_id = i.id
INNER JOIN FieldsTable f ON f.id = v.field_id
INNER JOIN FieldsItemRelationsTable v2 ON v2.item_id = i.id
INNER JOIN FieldsTable f2 ON f2.id = v2.field_id
WHERE v.value = 50 AND f.name = 'product_id'
AND (v2.value = 30 AND f2.name = 'hidden_key');
er...that query might not function (a bit of a copy/paste sludge job on my part), but you get the idea...you'll need the second value held in a second instance of the table(s) (v2 and f2 in my example here) that is seperate than the first instance. v1.value = 30 and v2.value = 50. v1.value = 50 and v1.value = 30 should never return rows as nothing will equal 30 and 50 at the same time
As an after thought...the query will probably read easier had you put the where clause in the join statement
SELECT i.* FROM ItemsTable i
INNER JOIN FieldsItemRelationsTable v ON v.item_id = i.id and v.value = 50
INNER JOIN FieldsTable f ON f.id = v.field_id and f.name = 'product_id'
INNER JOIN FieldsItemRelationsTable v2 ON v2.item_id = i.id and v2.value = 30
INNER JOIN FieldsTable f2 ON f2.id = v2.field_id and f2.name = 'hidden_key'
Functionally both queries should operate the same though. I'm not sure if there's a logical limit...in scheduling systems you'll often see a setup for 'exceptions'...I've got a report query that's joining like this 28 times...one for each exception type returned.
It's called EAV
Some people hate it
There are alternatives (SO)
Sorry to be vague, but I would investigate your options more.
Try doing some left or right joins to see if you get any results. inner joins will not return results sometimes if there are null fields.
its a start.
Dont forget though, outer join = cartesian product