Use SELECT as value for JOIN - sql

I have table ItemPropertyValue with unique ID and PropertyID
ID IDProperty Value ItemID
1 1 1 5
2 2 2 6
3 3 2 10
4 4 2 15
And another table called PropertyCategory
IDProperty Value Name
1 1 First Option
1 2 Second Option
2 1 Another option
What I want - it's to select PropertyID from first table ItemPropertyValue where ItemID = 10 and then join with second table PropertyCategory
So I have smth like this:
IDProperty Value Name
1 1 First Option
1 2 Second Option
2 1 Another option
I tried this but there is an error. No such column as PropertyID
SELECT * FROM PropertyCategory JOIN
(SELECT ItemPropertyValue.IDProperty AS PropertyID
WHERE ItemPropertyValue.IDItem = '10')
ON PropertyCategory.IDProperty = PropertyID
How can I do it?
MS SQLServer if any

Try Aliasing the subselect
SELECT * FROM PropertyCategory JOIN
(SELECT ItemPropertyValue.IDProperty AS PropertyID
WHERE ItemPropertyValue.IDItem = '10') a
ON PropertyCategory.IDProperty = a.PropertyID
Additionally, this would do well as a regular join with the filtrating happening in the outer WHERE clause, like
SELECT *
FROM PropertyCategory
JOIN ItemPropertyValue ON PropertyCategory.IDProperty = ItemPropertyValue.IDProperty
WHERE ItemPropertyValue.IDProperty = '10'
Finally, if you happen to be using SQL Server and really want to do it in a subselect-type of statement, I'd suggest checking out CROSS APPLY or OUTER APPLY for such an application.

Use table alias:
SELECT *
FROM PropertyCategory
JOIN
(SELECT ItemPropertyValue.IDProperty AS PropertyID
WHERE ItemPropertyValue.IDItem = '10') as T
ON PropertyCategory.IDProperty = T.PropertyID

I would go for something like
SELECT * FROM ItemPropertyValue JOIN PropertyCategory
ON ItemPropertyValue.IDProperty = PropertyCategory.IDProperty
WHERE ItemPropertyValue.ItemID=10
You can restrict to couple of field in your SELECT by replacing the * with fields.

you are doing fine, just add alias to table name and it will work
SELECT * FROM PropertyCategory a JOIN
(SELECT ItemPropertyValue.IDProperty AS PropertyID
WHERE ItemPropertyValue.IDItem = '10') b
ON a.IDProperty = b.PropertyID

Related

SQL query to check if user assigned with a specific value and does not a different value assigned to the same user?

We can have users with multiple valueIDs. In SQL Server I am trying to pull all users that have valueID of 3 but do not have valueID of 1 and 2. So Table A would have a user column and a valueID column.
How do I write a SQL query to do this?
Also, any good resources to get my SQL query skills up to par?
Much appreciated.
Try:
SELECT user
FROM A outer
WHERE valueID = 3
AND NOT EXISTS
(
SELECT 1
FROM A inner
WHERE
(
valueID = 1
OR valueID = 2
)
AND inner.user = outer.user
)
Here's one more.... (all users with valueid = 3 and nothing else)
SELECT [USER]
FROM A
GROUP BY [USER]
HAVING MAX(CASE WHEN valueid = 3 THEN 0 when valueid IN (1,2) THEN 1 END) = 0;
This query will return all users that have values (3 and 1) or (3 and 2) or just 3
select user
from mytable t1
where valueId = 3
and (select count(distinct valueId)
from mytable t2 where t2.user = t1.user
and valueId IN (1,2)) < 2
A simple way to get what you asked if you meant users with a value of 3 except those which also have values of 1 and 2
Select s.UserID From SomeTable s
Where s.UserID NOT In
(select s1s.UserID From SomeTable s1s
inner join SomeTable s2s On s1s.UserID = s2s.UserID
Where s1s.ValueId = 1 And s2s.ValueId = 2)
Or
Select s.UserID From SomeTable s
Left Join
(select s1s.UserID From SomeTable s1s
inner join SomeTable s2s On s1s.UserID = s2s.UserID
Where s1s.ValueId = 1 And s2s.ValueId = 2) both
Where both.userID is null
I'm not really sure what your table structure is, but it's likely the below query should work depending on column names...
SELECT user, valueID
FROM users
WHERE valueID = 3

How to exclude records with certain values in sql select

How do I only select the stores that don't have client 5?
StoreId ClientId
------- ---------
1 4
1 5
2 5
2 6
2 7
3 8
I'm trying something like this:
SELECT SC.StoreId FROM StoreClients
INNER JOIN StoreClients SC
ON StoreClients.StoreId = SC.StoreId
WHERE SC.ClientId = 5
GROUP BY StoreClients.StoreId
That seems to get me all the stores that have that client but I can't do the opposite because if I do <> 5 ill still get Store 1 and 2 which I don't want.
I'm basically trying to use this result in another query's EXISTS IN clause
One way:
SELECT DISTINCT sc.StoreId
FROM StoreClients sc
WHERE NOT EXISTS(
SELECT * FROM StoreClients sc2
WHERE sc2.StoreId = sc.StoreId AND sc2.ClientId = 5)
SELECT SC.StoreId
FROM StoreClients SC
WHERE SC.StoreId NOT IN (SELECT StoreId FROM StoreClients WHERE ClientId = 5)
In this way neither JOIN nor GROUP BY is necessary.
SELECT DISTINCT a.StoreID
FROM tableName a
LEFT JOIN tableName b
ON a.StoreID = b.StoreID AND b.ClientID = 5
WHERE b.StoreID IS NULL
SQLFiddle Demo
OUTPUT
╔═════════╗
║ STOREID ║
╠═════════╣
║ 3 ║
╚═════════╝
SELECT StoreId
FROM StoreClients
WHERE StoreId NOT IN (
SELECT StoreId
FROM StoreClients
Where ClientId=5
)
SQL Fiddle
You can use EXCEPT syntax, for example:
SELECT var FROM table1
EXCEPT
SELECT var FROM table2
<> will surely give you all values not equal to 5.
If you have more than one record in table it will give you all except 5.
If on the other hand you have only one, you will get surely one.
Give the table schema so that one can help you properly

Selecting max value from 2nd table in first table results

I have 2 tables as below-
Table I
ID DATE
1 05/11/12
2 23/11/12
3 29/11/12
4 04/10/12
5 20/11/12
And another table (IH) with the following info-
ID RECNO NOTE
1 1 Open
1 2 Update
1 3 Close
2 1 Open
2 2 Update
2 3 Hold
2 4 Close
3 1 Open
4 1 Open
4 2 Update
5 1 Open
I would like to output a result as shown below, displaying the Note field using the highest value of RecNo for each ID. So using the data above the output should be-
ID DATE NOTE
2 23/11/12 Close
3 29/11/12 Open
The code I have is-
SELECT I.ID, I.DATE, IH.NOTE FROM
I I, IH IH
JOIN (SELECT MAX([RECNO]) [RECNO] FROM
IH
GROUP BY RECNO) IH2 ON IH2.ID = IH.ID AND
IH2.[RECNO] = IH.[RECNO]
JOIN I I2 ON I2.ID = IH.ID WHERE
(I2.DATE>={TS ‘2012-11-22 00:00:002}) GROUP BY I2.ID
However when I execute the code I get-
Invalid Column Name 'RECNO'. Statement(s) could not be prepared.
How about this? Note, haven't tried it, I'm on my Mac at the moment.
SELECT I.ID, I.DATE, IH.NOTE
FROM I I
OUTER APPLY
(SELECT TOP 1 *
FROM IH
WHERE IH.ID = I.ID
ORDER BY RECNO DESC) IH
WHERE I.DATE >= '2012-11-22'
Your SQL is rather, uh, messy.
Assuming you are using SQL Server 2005 or greater, you can use the row_number() function, as follows:
SELECT I.ID, I.DATE, IH.NOTE
FROM I join
(select ih.*, ROW_NUMBER() over (PARTITION by id order by recno desc) as seqnum
from IH
) ih
on IH2.[RECNO] = IH.[RECNO] and seqnum = 1
WHERE I2.DATE>='2012-11-22 00:00:002'
This is assigning a sequence number in the IH table, for each id with the highest record number getting the value "1". The rest is just SQL.
Your original query is simply not correct syntactically, but I think this is what you want based on the description.
and another one
SELECT I.ID, I.DATE
,(Select TOP 1 IH.NOTE FROM IH where IH.ID=i.ID Order by Recno DESC) as Note
from I
WHERE
I.DATE>'20121122'
maybe this will help
SELECT a.ID, a.DATE, b.NOTE FROM a
inner join b on a.ID = b.ID
where b.recno in (select max(bb.recno)
from b as bb where bb.id = b.id)
http://sqlfiddle.com/#!3/fd141/2
If you don't mind the different identifiers, look at this solution:
select t1.MyID, t1.MyDate, y.Note
from t1
join
(
select MyID, max(RecNo) as RecNo
from t2
group by MyID
) x
on t1.MyID = x.MyID
left join
(
select *
from t2
) y
on t1.MyID = y.MyID
and x.RecNo = y.RecNo
where t1.MyDate >= '2012.11.22'
The complete solution is here: http://sqlfiddle.com/#!3/4ca09/3
Update: Oops, forgot to bring in the date in where clause. Updated SQL Fiddle and the query above.

CASE for joining sql tables

I need a help on sql database side. And i have
table 1 : ENTITY_TYPE
entity_type_id entity_name
1 Task
2 Page
3 Project
4 Message
5 User
and table 2 : MESSAGE , that contains message from each entity values like
message_id entity_type owner_tableid message
1 1 12 A message on task level
2 3 14 A message on project level
and I want select these message according to each entity type and details from its owner table using 'owner_tableid' ie a query like....
select * from MESSAGE JOIN
case entity_type when 1 then taskTable
when 2 then pageTable
when 3 then projectTable
when 4 then MessageTable
when 5 then UserTable
Which is best method to solve this issue on single procedure. Any idea ?? Now I am using IF clause for each entity...
You can't parameterise the tables involved in a query (so you can't put a table name in a variable and expect that to be used either).
One way to do it is as a chain of left joins:
select
* /* TODO - Pick columns */
from
MESSAGE m
left join
taskTable tt
on
m.entity_type = 1 and
m.owner_entity_id = tt.id
left join
pageTable pt
on
m.entity_type = 2 and
m.owner_entity_id = pt.id
left join
projectTable prt
on
m.entity_type = 3 and
m.owner_entity_id = prt.id
left join
MessageTable mt
on
m.entity_type = 4 and
m.owner_entity_id = mt.id
left join
UserTable ut
on
m.entity_type = 5 and
m.owner_entity_id = ut.id
If you want values from these tables to appear in a single column in the result, use a COALESCE across all of the values, e.g.
COALESCE(tt.Value,pt.Value,prt.Value,mt.Value,ut.Value) as Value
Use Union Clause with your individual entity_type
SELECT * FROM Message
JOIN pageTable ON ....
WHERE entity_type = 1
UNION ALL
..........
entity_type = 2
UNION ALL
..........
entity_type = 3
Select ...
From Message
Join (
Select 1 As entity_type, id
From taskTable
Union All
Select 2, id
From pageTable
Union All
Select 3, id
From projectTable
Union All
Select 4, id
From messageTable
Union All
Select 5, id
From userTable
) As Z
On Z.entity_type = Message.entity_type
And Z.id = Message.owner_tableid
If you need to return several entity_types details in one query, than UNION might help:
SELECT interesting_columns FROM Message
JOIN pageTable ON (joinPredicate)
WHERE entity_type = 1
UNION ALL
SELECT interesting_columns FROM Message
JOIN pageTable ON (joinPredicate)
WHERE entity_type = 2
-- ...
But if you only need details of certain entity_type than you original solution with IF would be much better.

Using (IN operator) OR condition in Where clause as AND condition

Please look at following image, I have explained my requirements in the image.
alt text http://img30.imageshack.us/img30/5668/shippment.png
I can't use here WHERE UsageTypeid IN(1,2,3,4) because this will behave as an OR condition and fetch all records.
I just want those records, of first table, which are attached with all 4 ShipmentToID .
All others which are attached with 3 or less ShipmentToIDs are not needed in result set.
Thanks.
if (EntityId, UsageTypeId) is unique:
select s.PrimaryKeyField, s.ShipmentId from shipment s, item a
where s.PrimaryKeyField = a.EntityId and a.UsageTypeId in (1,2,3,4)
group by s.PrimaryKeyField, s.ShipmentId having count(*) = 4
otherwise, 4-way join for the 4 fields,
select distinct s.* from shipment s, item a, item b, item c, item d where
s.PrimaryKeyField = a.EntityId = b.EntityId = c.EntityId = d.EntityId and
a.UsageTypeId = 1 and b.UsageTypeId = 2 and c.UsageTypeId = 3 and
d.UsageTypeId = 4
you'll want appropriate index on (EntityId, UsageTypeId) so it doesn't hang...
If there will never be duplicates of the UsageTypeId-EntityId combo in the 2nd table, so you'll never see:
EntityUsageTypeId | EntityId | UsageTypeId
22685 | 4477 | 1
22687 | 4477 | 1
You can count matching EntityIds in that table.
WHERE (count(*) in <tablename> WHERE EntityId = 4477) = 4
DECLARE #numShippingMethods int;
SELECT #numShippingMethods = COUNT(*)
FROM shippedToTable;
SELECT tbl1.shipmentID, COUNT(UsageTypeId) as Usages
FROM tbl2 JOIN tbl1 ON tbl2.EntityId = tbl1.EntityId
GROUP BY tbl1.EntityID
HAVING COUNT(UsageTypeId) = #numShippingMethods
This way is preferred to the multiple join against same table method, as you can simply modify the IN clause and the COUNT without needing to add or subtract more tables to the query when your list of IDs changes:
select EntityId, ShipmentId
from (
select EntityId
from (
select EntityId
from EntityUsage eu
where UsageTypeId in (1,2,3,4)
group by EntityId, UsageTypeId
) b
group by EntityId
having count(*) = 4
) a
inner join Shipment s on a.EntityId = s.EntityId