SQL: How to check "if this record exists then that record must also exist" for given ID set - mysql

my database table (DWInfo) looks like this:
InstanceID | AttributeID
1 | 1
1 | 2
1 | 3
2 | 1
2 | 4
3 | 1
3 | 2
There are several instances and every instance has multiple attributes.
What I want to achieve is this: for a given set/rule of id's I want to get all InstanceID's which violate the condition, for example let the given ID's be 1 and 2, which means if there is an instance with AttributeID=1, Attribute=2 should also exist for it. In this case the result would be instance two, because this instance violates the condition.
I tried it with JOINS but this only seemed effective for 2 attributes and not more.
Select * from DWInfo dw1 INNER JOIN DWInfo dw2 ON dw1.InstanceID = dw2.InstanceID where dw1.AttributeID != dw2.AttributeID and dw1.AttributeID = 1 AND dw2.AttributeID != 2
Is it possible to solve this problem with a SQL query?

Assuming that each InstanceId can have only one of each different AttributeId, i.e. a unique composite index (InstanceId, AttributeId):
SELECT InstanceID
FROM DWInfo
WHERE AttributeID IN (1,2)
GROUP BY InstanceID
HAVING SUM(AttributeId = 1) = 1
AND COUNT(*) < 2 /* Or SUM(AttributeId = 2) = 0 */
SQLFiddle DEMO
Note that if having AttributeId of 2 means that the instance requires an AttributeId of 1 also.. slightly different logic, this is neater:
SELECT InstanceID
FROM DWInfo
WHERE AttributeID IN (1,2)
GROUP BY InstanceID
HAVING COUNT(*) < 2

Where there exists Attribute 1 find the ones that don't have Attribute 2.
select InstanceID
from DWInfo
group by InstanceID
having
count(case when AttributeID = 1 then 1 end) > 0
and count(case when AttributeID = 2 then 1 end) = 0
This answer is basically the same as Arth's. You might find it beneficial to filter the Attributes in the where clause but it's not strictly necessary. I prefer the standard syntax using case expressions even though the shorthand would be handy if it were portable. I also prefer count over sum in these scenarios.
It's not clear whether you can have duplicates (probably not) and whether Attribute 2 can appear alone. You might have to tweak the numbers a bit but you should be able to follow the pattern.

I think this does what you want:
select instanceid
from dwinfo
where attributeid in (1, 2)
group by instanceid
having count(*) = 2;
This guarantees that you have two matching rows for each instance. If you can have duplicates, then use:
having count(distinct attributeid) = 2
EDIT:
For the conditional version (if 1 --> 2):
having max(attributeid = 2) > 0
That is, if it has 1 or 2, then it has to have 2, and everything is ok.

Related

combining two select queries from the same table

I need to do something like this:
id tag status user trial Value (other columns)...
1 A Pass peter first 0
2 A Pass peter second 1
3 A Fail peter third 3
4 B Pass peter first 4
5 B Pass peter second 5
6 B Pass peter third 6
select the rows that tag equal A and status equal to Pass and find the same value for other tag ex:B
id tag status user trial Value_tag_A Value_tag_B (other columns)...
1 A Pass peter first O 4
2 A Pass peter second 1 5
I can do some processing using php to get this result, but i'm wondering if i can do it directly using sql
I've tried numerous variations and can't seem to get close to the result.
Solution: http://sqlfiddle.com/#!9/e9068d/17
I don't know why in the rows where tag=A also have Value_tag_B. I will ignore this and maybe the following query is an approach.
SELECT DISTINCT y.status, y.`user`, y.trial,
(SELECT Value FROM toto WHERE y.`user` = `user` and y.trial = trial and tag = 'A' ) AS Value_tag_A,
(SELECT Value FROM toto WHERE y.`user` = `user` and y.trial = trial and tag = 'B' ) AS Value_tag_B
FROM toto y
WHERE y.trial NOT IN (SELECT DISTINCT trial FROM toto WHERE `status` <> 'Pass')
The code has been modified.
SQL Fiddle

SQL where particular column values appears

I wasn't sure how to really search for this..
Lets say I have a simple table like this
ID Type
1 0
1 1
2 1
3 0
4 0
4 1
How could I select all ID's which have a type of both 0 and 1?
SELECT id,type
FROM t
GROUP BY id
HAVING SUM(type=0)>0
AND SUM(type=1)>0
You just group by id ,than with HAVING you use post aggregation filtering to check for 0 and 1.
Having is pretty expensive and that query can't hit keys.
SELECT ID FROM foo AS foo0 JOIN foo AS foo1 USING (ID) WHERE foo0.Type=0 AND foo1.Type=1 GROUP BY foo0.id.
A more generalized way of doing this would by to use a CASE column for each value you need to test combined with a GROUP BY on the id column. This means that if you have n conditions to test for, you would have a column indicating if each condition is met for a given id. Then the HAVING condition becomes trivial and you can use it like any multi-column filter, or use the grouping as your subquery and the code looks simpler and the logic becomes even easier to follow.
SELECT id, Type0,Type1
FROM (
SELECT id,
Type0 = max(CASE WHEN type = 0 THEN TRUE END)
, Type1 = max(CASE WHEN type = 1 THEN TRUE END)
FROM t
GROUP BY id
) pivot
WHERE Type0 = TRUE and Type1 = TRUE

How to select vertical data in MySQL table

If I have a table like this:
ID color size weight
1 red 2 3
2 green 4 5
So to run a mysql query to find the ID number that is color:red and size:2 and weight:3 I can do this:
select ID from table where color=red AND size=2 AND weight=3
As properties are growing in addition to color, weight, size, mileage, speed, etc... and I want to keep the table scaling it would make sense to organize it this way
ID ID2 property value
1 1 color red
2 1 size 2
3 1 weight 3
4 2 color green
5 2 size 4
6 2 weight 5
How do I run a select query here to find the ID number that is color:red and size:2 and weight:3
For key value structure one approach is to self join as many times as the no. of properties you have like in your case 3 properties (color,weight,size) so you need 2 self joins and for each,filter results according to properties like in below query i have given unique aliases so for the alias t i have filtered rows with t.property = 'color' and for value t.value = 'red' and same as for other aliases to find the desired ids which fits for the provided criteria,So if your criteria increases with another property you need another self join and same filtering as above
select t.id2
from test t
join test t1 on(t.id = t1.ID2)
join test t2 on(t.id = t2.ID2)
where t.property = 'color'
and t1.property = 'size'
and t2.property = 'weight'
and t.value = 'red'
and t1.value = '2'
and t2.value = '3'
DEMO
If there's a lot of properties (only a few of which may be of interest), you may be better off with the Star schema that was specifically invented for this case.
Less than 10 properties you described are hardly a justification for such complication though. You'll be just fine with the initial table in accordance with the KISS principle.

SQL: Get column where it contains 1 or another

This is an "either or" kind of query that I can't figure out the best way to approach
SELECT id, serial_number FROM bid_tag WHERE active = 1 AND house_id = 0 OR house_id = 14
So I need to get a house_id that is either 0 or a specific number of "14"
Parentheses are your friend. If you don't use them, logical expressions will be evaluated in the wrong order (in your case, not active items could be listed as well):
active = 1 AND (house_id = 0 OR house_id = 14)
You can also use IN(), more handy if you have several options:
active = 1 AND house_id IN (0, 14)

Using IN clause in sql server

My query is like below.I want to select values if Type = 1 and subtype = 1,3 or 2.
select sum(case when Type = 1 and SubType in (1, 3 or 2) then 1 else 0 end) as 'WorkStations'
Is this right way?
Since you're only trying to get a count of the workstations that meet the criteria as far as I can see:
SELECT COUNT(*) AS Workstations FROM MyWorkStationTable WHERE Type = 1 AND SubType IN (1, 2, 3)
Also, an IN clause is by nature already an OR. It is neither valid syntax nor necessary to state it.
If you're simply counting records, your best bet is to use the COUNT function provided by SQL Server. Consider using the following:
SELECT COUNT(*) FROM [Table] WHERE TYPE = 1
AND (SUBTYPE = 1
OR SUBTYPE = 2
OR SUBTYPE = 3)
It is best to avoid using 'IN' as it can lead to unnecessary calls to the SQL engine.
SELECT COUNT(*) [Workstations] FROM [YourTable] t WHERE t.Type = 1 AND t.SubType IN (1, 2, 3)
Try avoiding IN Predicates and instead use Joins because it Iterate unnecessarily despite of the fact that there is just one/two match. I will explain it with an example.
Suppose I have two list objects.
List 1 List 2
1 12
2 7
3 8
4 98
5 9
6 10
7 6
Using IN, it will search for each List-1 item in List-2 that means iteration will happen 49 times !!!