sql query for multi valued attributes - sql

I have resources each represented by a guid and they have attribute name-value pairs. I would like to query
for resources which have the given attribute name value pairs.
So, suppose the table looks like:
GUID ATTR_SUBTYPE ATTR_VAL
63707829116544a38c5a508fcde031a4 location US
63707829116544a38c5a508fcde031a4 owner himanshu
44d5bf579d9f4b9a8c41429d08fc51de password welcome1
44d5bf579d9f4b9a8c41429d08fc51de host retailHost
c67d8f5d1a9b41428f029d55b79263e1 key random
c67d8f5d1a9b41428f029d55b79263e1 role admin
and I want all the resources with location as US and owner as olaf.
One possible query would be:
select guid from table where attr_subtype = 'location' and attr_value = ‘US'
INTERSECT
select guid from table where attr_subtype = 'owner' and attr_value = ‘himanshu';
There can be any number of attribute name value pairs in the query, so an additional intersection per pair
in the query. I was wondering if we can construct a better query as intersection is expensive.

Assuming you don't have duplicate attributes per GUID you can achieve the desired result without a JOIN:
SELECT "GUID" FROM T
WHERE ( "ATTR_SUBTYPE" = 'location' AND "ATTR_VAL" = 'US' )
OR ( "ATTR_SUBTYPE" = 'owner' AND "ATTR_VAL" = 'himanshu' )
GROUP BY "GUID"
HAVING COUNT(*) = 2 -- <-- keep only GUID have *both* attributes
See http://sqlfiddle.com/#!4/80900/2

Generally, JOIN would be better than INTERSECT here. It gives a chance to get first records prior than several full table scans will finish. But anyway you select a slow data structure so it wouldn't wonderful if it slowdown.
Try something like
select *
from
(select * from table where attr_subtype = 'location' and attr_value = 'US') t1
join
(select * from table where attr_subtype = 'owner' and attr_value = 'himanshu') t2
on (t1.guid = t2.guid)
...

Insert your targets into a temp table then join to it.
select t.guid
from table as t
join temp
on t.attr_subtype = temp.attr_subtype
and t.attr_value = temp.attr_value

Related

Select rows having value combination listed in another table

I have tables:
Result containing 5 columns: result_id, num_1, num_2, num_3, num_4
Ref containing 4 columns: num_1, num_2, num_3, num_4
Columns num contain random int in range of 1-9
Aim of exercise is to display all result_id from Result table which have num values combination present in Ref table and to display result_id which have not met combination criteria.
I've been trying left joining ref to result, but unfortunately no success. Could you please share some light how to deal with it?
If you want the result_id for which combination exists in the ref table then use following JOIN query:
select distinct r.result_id
from results r
join ref on r.num_1 = ref.num_1 and r.num_2 = ref.num_2
and r.num_3 = ref.num_3 and r.num_4 = ref.num_4
If you want the result_id for which combination do not exists in REF table then use the LEFT JOIN as follows:
select r.result_id
from results r
left join ref on r.num_1 = ref.num_1 and r.num_2 = ref.num_2
and r.num_3 = ref.num_3 and r.num_4 = ref.num_4
where ref.num_1 is null -- or use PK / Not nullable column of REF table here
Assuming you want the columns to "line up" and you want to add a flag to the result_id in the first table, then use exists:
select t1.*,
(case when exists (select 1
from table2 t2
where t2.n1 = t1.n1 and t2.n2 = t1.n2 and t2.n3 = t1.n3 and t2.n4
)
then 'present' else 'not present'
end) as flag
from t2;

postgres: query results into variables to be used later

I have what will end up being a complex query where certain parts will often be repeated. I would therefore like to store the results of some sub queries into variables which can then be used in the main query.
For example I would like to set the variable 'variable_id' to be equal to a SELECT query and variable_school_id to be equal to another SELECT query:
variable_id integer := (SELECT id FROM account WHERE email = 'test#test.com');
variable_school_id integer := (SELECT school FROM account WHERE email = 'test#test.com');
Then I would like to make use of those variables in a query that would look like:
select * from doctor where account_id = variable_id AND school = variable_school_id ;
How do I go about doing this?
Can't you just use CTEs?
with params as (
SELECT id, school
FROM account
WHERE email = 'test#test.com'
)
select d.*
from params cross join
doctor d
on d.account_id = params.id and d.school = params.school;

How to write a query to get data count with combination of codision

I have two tables named [DrugPrescriptionEdition] and [PrescriptionDoseDetail] and now, I join that two tables using the below query and taking a result set.
select * from DrugPrescription dp where id in(
SELECT distinct dpe.template
FROM [DrugPrescriptionEdition] dpe
join PrescriptionDoseDetail pdd on pdd.prescription = dpe.id
where doseEnd_endDate is NULL and doseEnd_doseEndType =1
)
but now I want to take records only contain, (1,2) combination of 'datasource' column and prescription.id should be same.
Example : like records { prescriptionID =4 and there contain ,(1,2) }. I will not consider, only 1 ,or 2 contain records.
Need some expert help to adding this conditions to my above query and modify it .
Expected result : I need to filter out , above query result using this, new condition too.
Let me assume your records are in a single table. Here is one method:
select t.*
from t
where (t.dataSource = 1 and
exists (select 1
from t t2
where t2. prescriptionid = t.prescriptionid and
t2.dataSource = 2
)
) or
(t.dataSource = 2 and
exists (select 1
from t t2
where t2.prescriptionid = t.prescriptionid and
t2.dataSource = 2
)
);
It is unclear if any other data sources are allowed. If they are not, then add:
and
not exists (select 1
from t t3
where t3.prescriptionid = t.prescriptionid and
t3.dataSource not in (1, 2)
)

Case statement causing error - No column name was specified for column 4 of 'a'

This query is designed so that each row will have a unique NAME value.
The query works fine except when I introduced the SELECT CASE statement to select ROLENAME. When this is added, I get the error
No column name was specified for column 4 of 'a'.
How can this be resolved?
SELECT *
FROM
(SELECT
NAME, CREATE_DATE, OTHERNAME,
CASE
WHEN ID = 'test' THEN ROLENAME
END,
STATUS,
ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY NAME DESC) AS RowNumber
FROM
BUSRULES br1
INNER JOIN
BUSRULES br2 ON br1.ID_NUM = br2.ID_NUM
INNER JOIN
BUSRULES br3 ON br1.ID_NUM = br3.ID_NUM
INNER JOIN
dbo.MDI ON NAME = br3.VALUE_TXT
INNER JOIN
(PERSON
LEFT JOIN
OP_TYPE ON OP_CASE.ID_NUM = OP_TYPE.ID_NUM)
ON OP_ID_NUM = OCO_OP_ID_NUM
WHERE
br1.KEY_TXT = 'EVENT'
AND br1.VALUE_TXT = 'YES'
AND br2.ABR_KEY_TXT = 'LIST'
AND br2.ABR_VALUE_TXT = 'test'
AND br3.ABR_KEY_TXT = 'NAME') AS a
WHERE
a.RowNumber = 1
Try to modify :
CASE WHEN ID = 'test'
THEN ROLENAME
END
into :
CASE WHEN ID = 'test'
THEN ROLENAME
END AS ROLENAME
The reason is because when you use CASE clause, it will have no name, unless you define it
The error message is very specific - you don't have a column alias for the column you're creating with your CASE statement.
, CASE WHEN ID = 'test'
THEN ROLENAME
END AS SomeColumnName -- Add a column name alias here
It's extremely important to learn to actually read the words in error messages. They usually contain some relevant information. It's also important to learn where to find the documentation for the DBMS you're using, as it would have told you what the requirements were for CASE and shown examples of using it.

Select query and unknow predicate value

I have this table with this columns: Key,Type,Culture.
Key and Culture are PK.
I know the Key and Culture values before query execution.
select * from resources r where r.CULTURE = 'sk' and r.KEY = 'test';
But I'd like to perform a select which would select also all other records with the same Type as the record with Culture = 'sk' and Key = 'test'
SELECT * FROM resources AS r WHERE r.type =
(SELECT type FROM resources s where s.culture= 'sk' and s.key= 'test')
culture and key are PK, so you only get one value back for type for your subquery. That result is used to get all rows with that type. If the subquery would return multiple values, you can use IN instead of =.
Use a join, it could resolves performance issue.
SELECT r.*
FROM resources r
INNER JOIN resources r2
ON r.type = r2.type
WHERE r2.CULTURE = 'sk'
AND r2.KEY = 'test'