Compare two rows in AND condition - sql

just having a problem using the AND operator in SQL as it returns a zero result set.
I have the following table structure:
idcompany, cloudid, cloudkey, idsearchfield, type, userValue
Now I execute the following statement:
SELECT *
FROM filter_view
WHERE
(idsearchfield = 4 and compareResearch(userValue,200) = true)
AND (idsearchfield = 6 and compareResearch(userValue,1) = true)
compareResearch ist just a function that casts the userValue and compares it to the other value and returns true if the value is equal or greater. UserValue is actually stored as a string (that's a decision made 6 years ago)
Okay, I get a zero resultset which is because both criterias in braces () are AND combined and one row can only have one idsearchfield and therefor one of the criterias won't match.
How do I get around this? I NEED the AND Comparison, but it won't work out this way.
I hope my problem is obvious :-)

If you've recognised that both conditions can't ever both be true, in what way can the AND comparison be the correct one?
select *
from filter_view
where (idsearchfield = 4 and compareResearch(userValue,200) = true)
OR (idsearchfield = 6 and compareResearch(userValue,1) = true)
This will return 2 rows (or more). Or are you looking for some way to correlate these two rows so that they appear as a single row?
Okay, so making a tonne of assumptions, because you haven't included enough information in your question.
filter_view returns a number of columns, one of which is some form of record identifier (lets call that ID). It also includes the aforementioned idsearchfield and userValue columns.
What you actually want to find is those id values, for which one row of filter_view has idsearchfield = 4 and compareResearch(userValue,200) = true and another row of filter_view has idsearchfield = 6 and compareResearch(userValue,1) = true
The general term for this is "relational division". In this simple case, and assuming that id/idsearchfield are unique in this view, we can answer it with:
select id,COUNT(*)
from filter_view
where (idsearchfield = 4 and compareResearch(userValue,200) = true)
OR (idsearchfield = 6 and compareResearch(userValue,1) = true)
group by id
having COUNT(*) = 2
If this doesn't answer your question, you're going to have to add more info to your question, including sample data, and expected results.

Related

Ignore clauses in where based on if you get a result from the select

I want the following sql statement to give me different results based on whether it finds a result within the specific string or it needs to search the whole parent group (so within the table there are for example:
column 1, column 2
a - 1
a - 2
a - 3
b - 5
b - 7
b - 1
so if it can find the result if i put 1 it will display me
a -1
b -1
. the problem is that in the where clause exist both the parent group and the child group
i have tried to use case and also to simulate an if with ands and ors but it didn't work
select 1,
aapv.aapv_keyext1,
aapv.aapv_area,
aapv.aapv_valuecharmax,
aapv.aapv_valuechardefault,
aapv.aapv_valuecharmin, aap.aap_ident
from a_parameter_value aapv,
a_parameter aap
where aap.aap_ident in (string1,string2,string3)
and aap.aap_ref = aapv.aap_ref
and aap.aap_idento = string4
and ((aapv.Aapv_Keyext1 = 'LaD1' --child clause
and aapv.aapv_keyext1 is not null)
or aapv.Aapv_Area = 'LSDe' --parent clause
and aapv.Aapv_Area is null)
I expect the output to be if the aapv_keyext1 value finds any results then the appv_area is not used at all but either only the child clause is used with the above code or both if i remove the is null clause
Okay, you need to provide more information for us to give you a real answer, but I wanted to point out that this section has some logic problems:
and ((aapv.Aapv_Keyext1 = 'LaD1' --child clause
and aapv.aapv_keyext1 is not null)
or aapv.Aapv_Area = 'LSDe' --parent clause
and aapv.Aapv_Area is null)
The first part is saying aapv_keyext1 = 'LaD1' AND aapv_keyext1 is not null; the second half can never be false, so it's redundant. The second part is saying aapv_area = 'LSDe' AND aapv_area is null. This will never be true. So this whole section is equivalent to:
and (aapv.aapv_keyext1 = 'LaD1')
Which probably isn't what you want. You say you want "if the aapv_keyext1 value finds any results then the appv_area is not used at all". I suspect what you mean is that "if any results exist for aapv_keyext1 in any rows then don't use aapv_area" which is more complicated, you need a subquery (or analytic/aggregate functions) to look at what other rows are doing.
select 1,
aapv.aapv_keyext1,
aapv.aapv_area,
aapv.aapv_valuecharmax,
aapv.aapv_valuechardefault,
aapv.aapv_valuecharmin, aap.aap_ident
from a_parameter_value aapv,
a_parameter aap
where aap.aap_ident in (string1,string2,string3)
and aap.aap_ref = aapv.aap_ref
and aap.aap_idento = string4
and (-- prefer keyext1
aapv.Aapv_Keyext1 = 'LaD1'
OR
-- if keyext1 doesn't find results...
(NOT EXISTS (select 1 from a_parameter_value aapv2
where aapv2.aap_ident = aap.aap_ident
and aap2.aap_ref = aap.aap_ref
and aap2.aap_idento = aap.aap_idento
and aapv.Aapv_Keyext1 = 'LaD1')
AND
-- ... use aapv_area
aapv.Aapv_Area = 'LSDe')
);
You can also do this kind of conditional logic with CASE statements, but you're still going to need a subquery or something if you want your logic to depend on the values in rows other than the one currently being looked at.
Let me know if I've misunderstood your question and I'll try to update with a better answer.

Applying the count function within the case function

I am relatively new to SQL and am trying to apply the case function within a view.
While I understand the fundamentals of it, I am having difficulty applying it in the way that I need.
I have 3 columns ApplicationID, ServerName and ServerShared? (true/false).
Each application can have many servers associated to it, while each server only has 1 server type.
I would like to use case to create a further field which can take three values dependent upon whether the values of ServerShared related to an application are all True = Shared, False = Non-shared, Both True and False = Partially shared.
My thoughts were using count function within the case function to set statements where:
if 'count true > 0 and count false > 0' then ServerShared? =
partially if 'count true > 0' and 'count false = 0' then
ServerShared = true and vice versa.
I believe the above logic a way of achieving my result, yet I would appreciate help in both how to structure this within a case statement and any wisdom if there is a better way.
Thanks in advance!
If I get your question right, this should do the trick. Maybe you need to add further columns or adapt the logic. But you should get the logic behind.
SELECT ServerName,
CASE
WHEN COUNT(distinct ServerShared) = 2
THEN N'Server shared'
WHEN MIN(ServerShared) = 0
THEN N'Server not shared'
WHEN MAX(ServerShared) = 1
THEN N'Server shared'
END as ServerShared
FROM myTable
GROUP BY ServerName
There are two main ways to do this problem (super generic answer from non expert :D)
less often executed (one off?), slow execution with potential exponential time increases as rows go up:
This is similar to your suggested solution and involves putting other queries in the Select / field list part of the query - this will get executed for every row returned by the main part of the query (bad news generally speaking):
select
applicationID
, Case (select count * from table as b where a.applicationid = b.applicationid and shareserver=true)
WHEN 0 then 'Non-Shared'
WHEN (select count * from table where a.applicationid = b.applicationid) then 'Shared'
ELSE 'Partially-Shared' END as ShareType
from
tabls as a
get all your data once then perform just the comparison row by row. this is what i would use by default.. its basically better as far as i know but sometimes can be harder to think through.
this line is here to fix formatting issue
select
a.applicationid
,case
when sharedservers = 0 then 'Non-Shared'
when totalservers=sharedservers then 'Shared'
else 'Partially-Shared' END as ShareType
FROM
(select applicationID, count(*) as TotalServers from table) as a
LEFT OUTER JOIN (select applicationID, count(*) as SharedServersfrom table where sharedserver = true) as b
ON a.applicationid=b.applicationid
these queries are just written off the top of my head let me know if there are bug :/
note also the two uses of case statement. one with CASE *value* WHEN *possible value* THEN .. and the second way CASE WHEN *statement that evaluates to boolean* THEN ..

Creating filter with SQL queries

I am trying to create a filter with SQL queries but am having trouble with numeric values linking to other tables.
Every time I try to link to another table, it takes the same record and repeats it for every element in the other table.
For example, here is query:
SELECT ELEMENTS.RID,TAXONOMIES.SHORT_DESCRIPTION,[type],ELEMENT_NAME,ELEMENT_ID,SUBSTITUTION_GROUPS.DESCRIPTION,namespace_prefix,datatype_localname
FROM ELEMENTS,SUBSTITUTION_GROUPS,TAXONOMIES,SCHEMAS,DATA_TYPES
WHERE ELEMENTS.TAXONOMY_ID = TAXONOMIES.RID AND ELEMENTS.ELEMENT_SCHEMA_ID = SCHEMAS.RID AND
ELEMENTS.DATA_TYPE_ID = DATA_TYPES.RID
AND ELEMENTS.SUBSTITUTION_GROUP_ID = 0
The last line is the actual filtering criteria.
Here is an example result:
There should only be ONE result (Item has an RID of 0). But it's repeating a copy of the one record for every result inside the substitution groups table (there's 4).
Here is my database schema for reference. The lines indicate relationships between tables and the circles indicate the values I want:
You're forgot to join between ELEMENTS and SUBSTITUTION_GROUPS in your query.
SELECT
ELEMENTS.RID,TAXONOMIES.SHORT_DESCRIPTION,[type],ELEMENT_NAME,ELEMENT_ID,SUBSTITUTION_GROUPS.DESCRIPTION,namespace_prefix,datatype_localname
FROM
ELEMENTS,SUBSTITUTION_GROUPS,TAXONOMIES,SCHEMAS,DATA_TYPES
WHERE
ELEMENTS.TAXONOMY_ID = TAXONOMIES.RID AND ELEMENTS.ELEMENT_SCHEMA_ID = SCHEMAS.RID
AND ELEMENTS.DATA_TYPE_ID = DATA_TYPES.RID
AND ELEMENTS.SUBSTITUTION_GROUP_ID = SUBSTITUTION_GROUPS.RID
AND ELEMENTS.SUBSTITUTION_GROUP_ID = 0

I'm looking for a LINQ solution to create a sub-list where items w/ duplicate property values are skipped

The problem is: I have a list of objects, with some containing the same PlanId property value. I want to only grab the first occurrence of those and ignore the next object with that PlanId. The root problem is a View in the database, but it's tied in everywhere and I don't know if changing it will break a ton of stuff nearing a deadline, so I'm tossing in a hack for now.
So, if I have a list of PlanObjects like such.
Plan1.PlanId = 1
Plan2.PlanId = 1
Plan3.PlanId = 2
Plan4.PlanId = 3
Plan5.PlanId = 4
Plan6.PlanId = 4
I want to take a sub-list from that with LINQ (italics mean an item is not included)
Plan1.PlanId = 1
Plan2.PlanId = 1
Plan3.PlanId = 2
Plan4.PlanId = 3
Plan5.PlanId = 4
Plan6.PlanId = 4
For my needs, it doesn't matter which one is taken first. The Id is used to update a datbase record.
If I didn't explain that well enough, let me know and I'll edit the question. I think it makes sense though.
PlanObjects.GroupBy(p => p.PlanId).Select(r => r.First());
The other answer (and its comments) supplies the fluent interface solution. Here's the query syntax:
From p In PlanObjects Group By p.PlanId Into First Select First

Many conditions in the WHERE clause of a SQL query

Hi I'm having trouble writing a query. I will be very glad to receive some advice!
My table is called TagObjects; it has 5 columns, but the 3 important to the problem are: tob_tag, tob_object and tob_objectType.
What I need to achieve with the query is the following: with an unknown number of pairs (tob_object, tob_objectType) I need to know all the tob_tag all the pairs have in common.
I have tried with this query (the numbers are just as an example):
SELECT "TagsObjects"."tob_tag"
FROM "TagsObjects"
WHERE TRUE
AND ("TagsObjects"."tob_object" = 8 AND "TagsObjects"."tob_objecttype" = 1)
AND ("TagsObjects"."tob_object" = 9 AND "TagsObjects"."tob_objecttype" = 1)
GROUP BY "TagsObjects"."tob_tag";
The WHERE TRUE is there because I'm building the query dynamically. This query works for one pair (one AND in the WHERE clause), when I tried it with two pairs (like the example I post above) it doesn't return any rows (and the data is there!).
If someone knows what I'm doing wrong or a way to do this it will be a BIG HELP!
Using PostgreSQL 9.0.1.
When building your optional clauses, do them using this pattern
SELECT "TagsObjects"."tob_tag"
FROM "TagsObjects"
WHERE FALSE
OR ("TagsObjects"."tob_object" = 8 AND "TagsObjects"."tob_objecttype" = 1)
OR ("TagsObjects"."tob_object" = 9 AND "TagsObjects"."tob_objecttype" = 1)
GROUP BY "TagsObjects"."tob_tag";
However, if there are no conditions at all, then add OR TRUE to the list, so it becomes
SELECT "TagsObjects"."tob_tag"
FROM "TagsObjects"
WHERE FALSE
OR TRUE
GROUP BY "TagsObjects"."tob_tag";
As for this part
I need to know all the tob_tag all the pairs have in common.
If you only want tob_tags that have both 8/1 and 9/1 (or more combinations), then you need a GROUP BY and HAVING clause.
SELECT "TagsObjects"."tob_tag"
FROM "TagsObjects"
WHERE FALSE
OR ("TagsObjects"."tob_object" = 8 AND "TagsObjects"."tob_objecttype" = 1)
OR ("TagsObjects"."tob_object" = 9 AND "TagsObjects"."tob_objecttype" = 1)
GROUP BY "TagsObjects"."tob_tag"
HAVING COUNT(*) = 2;
Let's start with what's wrong. You are trying to find a row where both "TagsObjects"."tob_object" = 8 and "TagsObjects"."tob_object" = 9. The "TagsObjects"."tob_object" cannot be both at the same time so no rows cannot be returned.
What you should do then?
From you specification I gather that there are several pairs of ("TagsObjects"."tob_object", "TagsObjects"."tob_objectType") where neither field is a constant. You want to create an union of all rows that are returned for each pair.
WITH matchingTagsObjects AS (
SELECT "TagsObjects"."tob_tag"
FROM "TagsObjects"
WHERE ("TagsObjects"."tob_object" = 8 AND "TagsObjects"."tob_objecttype" = 1)
UNION ALL
SELECT "TagsObjects"."tob_tag"
FROM "TagsObjects"
WHERE ("TagsObjects"."tob_object" = 9 AND "TagsObjects"."tob_objecttype" = 1)
)
SELECT "TagsObjects"."tob_tag"
FROM matchingTagsObjects
GROUP BY "TagsObjects"."tob_tag";
The named subquery matchingTgsObjects lists all tob_tags that are found for pairs (8,1) and (8,2). The actual tags are selected in the main query and distinct tob_tags are selected using the group by clause as with you solution. I used UNION ALL because the grouping is done in the main query and I didn't find any reason to prune duplicate rows in the subquery at this point. You can achieve that by leaving out the ALL from UNION ALL.
You can also include the subquery directly in the from part instead of using a named subquery.
There's also an alternative that you use OR conditions in the where clause as in WHERE (matches pair A) OR (matches pair B). A co-worker of mine would go ballistic if he saw that used: when an OR is needed to for matching in this kind of scenario it tells that there might be something to be done with actual model.