Is there any query to find this id information? - sql

Her is a sample of my table:
+--------+-------+-----+
| name | value | id |
+--------+-------+-----+
| value1 | 1 | 100 |
| value2 | 2 | 100 |
| value1 | 1 | 200 |
| value2 | 3 | 200 |
| value1 | 1 | 300 |
| value2 | 4 | 300 |
| | | |
+--------+-------+-----+
How to setup an SQL query to retrieve the id value 100 for given value1 = 1 and value2 = 2?

If I understand correctly, aggregation with a having clause does what you want:
select id
from t
group by id
having count(*) filter (where name = 'value1' and value = 1) = 1 and
count(*) filter (where name = 'value2' and value = 2) = 1 ;

Group by id and set the condition in the having clause:
select id
from tablename
where (name, value) in (('value1', 1), ('value2', 2))
group by id
having count(distinct value) = 2
See the demo.

A case of relational-division. See:
How to filter SQL results in a has-many-through relation
This query typically more efficient than what has been suggested so far:
SELECT id
FROM (SELECT id FROM tbl WHERE name = 'value1' AND value = 1) t1
JOIN (SELECT id FROM tbl WHERE name = 'value2' AND value = 2) t2 USING (id);
Or equivalent (results in identical query plan):
SELECT id
FROM tbl t1
JOIN tbl t2 USING (id)
WHERE t1.name = 'value1' AND t1.value = 1
AND t2.name = 'value2' AND t2.value = 2;
db<>fiddle here
Not enforcing uniqueness in the query (like other answers do) as I assume one or more constraints in the table already doing so.
Have a "covering" index on (name, value, id). Optimized index variations are possible, depending on your undisclosed table definition.
But first reconsider your relational design if you are in a position to change it. EAV models are typically sub-optimal. See:
Is there a name for this database schema of key values?

SELECT id from TABLE_NAME WHERE value IN (1, 2);
This is will retrieve the id column from your table when value column is either 1 or 2

Related

how do I make a query which references other rows in a resultset?

The question is best asked with an example.
I have a table
id | name | attr
1 | foo | a
2 | bar | a
3 | baz | b
and I want a query give me all the rows which share the same attr as 'name==foo', and thus returns
id | name | attr
1 | foo | a
2 | bar | a
because foo has attr=a, as does bar
You can use exists:
select t.*
from mytable t
where exists (
select 1 from mytable t1 where t1.attr = t.attr and t1.name = 'foo'
)
Note that this solution would also properly work if 'foo' had more than one attribute.
For performance, you want an index on (attr, name).
A simple way is a correlated subquery:
select t.*
from t
where t.attr = (select t2.attr from t t2 where t.name = 'foo');

Select ALL records with fieldvalue1 if any records (with fieldvalue1) have fieldvalue3 have a specific value

I need to show all records for a specific value if ANY one of those records have another specific value. Essentially, if field3 = 'b', what is field1? Show all records with value of field1 regardless of their field3 value.
Record Number External Id Letter
1 123456 a
2 123456 b
3 123456 c
4 456852 t
5 456852 b
record 2 has a letter value of 'b' - so I want to look at externalid, which is 123456, now I want to pull all records for external id regardless if the other records have a letter value of 'b'
Use EXISTS and a correlated subquery:
SELECT *
FROM mytable t
WHERE
t.letter = 'b'
OR EXISTS (
SELECT 1
FROM mytable t1
WHERE
t1.record_number != t.record_number
AND t1.external_id = t.external_id
AND t1.letter = 'b'
)
Another option is to use a window function:
SELECT record_number, external_id, letter
FROM (
SELECT
t.*,
MAX(CASE WHEN letter = 'b' THEN 1 END) OVER(PARTITION BY external_id) mx
FROM mytable t
) x WHERE mx = 1
Demo on DB Fiddle:
record_number | external_id | letter
------------: | ----------: | :-----
1 | 123456 | a
2 | 123456 | b
3 | 123456 | c
4 | 456852 | t
5 | 456852 | b
Use exists, but don't worry about filtering in the outer query:
select t.*
from t
where exists (select 1
from t t2
where t2.external_id = t.external_id and t2.letter = 'b'
);
With an index on (external_id, letter), I would expect this to have very good performance.

SQL Select a group when attributes match at least a list of values

Given a table with a (non-distinct) identifier and a value:
| ID | Value |
|----|-------|
| 1 | A |
| 1 | B |
| 1 | C |
| 1 | D |
| 2 | A |
| 2 | B |
| 2 | C |
| 3 | A |
| 3 | B |
How can you select the grouped identifiers, which have values for a given list? (e.g. ('B', 'C'))
This list might also be the result of another query (like SELECT Value from Table1 WHERE ID = '2' to find all IDs which have a superset of values, compared to ID=2 (only ID=1 in this example))
Result
| ID |
|----|
| 1 |
| 2 |
1 and 2 are part of the result, as they have both A and B in their Value-column. 3 is not included, as it is missing C
Thanks to the answer from this question: SQL Select only rows where exact multiple relationships exist I created a query which works for a fixed list. However I need to be able to use the results of another query without changing the query. (And also requires the Access-specific IFF function):
SELECT ID FROM Table1
GROUP BY ID
HAVING SUM(Value NOT IN ('A', 'B')) = 0
AND SUM(IIF(Value='A', 1, 0)) = 1
AND SUM(IIF(Value='B', 1, 0)) = 1
In case it matters: The SQL is run on a Excel-table via VBA and ADODB.
In the where criteria filter on the list of values you would like to see, group by id and in the having clause filter on those ids which have 3 matching rows.
select id from table1
where value in ('A', 'B', 'C') --you can use a result of another query here
group by id
having count(*)=3
If you can have the same id - value pair more than once, then you need to slightly alter the having clause: having count(distinct value)=3
If you want to make it completely dynamic based on a subquery, then:
select id, min(valcount) as minvalcount from table1
cross join (select count(*) as valcount from table1 where id=2) as t1
where value in (select value from table1 where id=2) --you can use a result of another query here
group by id
having count(*)=minvalcount

Postgres: "Recursive" query with Array

I have a database (that I can't change) one table looks like that:
| ID:integer | fk:integer | next:[integer array] |
--------------------------------------------------
| 1 | 711 | {4} |
| 2 | 712 | {6} |
| 3 | 788 | |
| 4 | 799 | {7} |
--------------------------------------------------
Now I try to define one Query that as first row the data with ID = 1 and as next rows, all data with the ID that are in the integer array next ({4}) so that my query returns:
| ID:integer | fk:integer | next:[integer array] |
--------------------------------------------------
| 1 | 711 | {4} |
| 4 | 799 | {7} |
--------------------------------------------------
But then stops, so it only results the element with the specified ID and it's next elements.
I tried sth. like this, but I can't get it to work:
SELECT * FROM tablenm WHERE ID = ANY(SELECT next FROM tablenm WHERE ID = 1) AND ID = 1
The current Workaround I use is to first use this query:
SELECT * FROM tablenm WHERE ID = 1
And then for each element in the Array I run the same query with the IDs in a loop programmatically, but this looks like a dirty hack and I hope there is a solutions for this with 1 SQL statement.
You can use = ANY(array) in the JOIN condition:
SELECT t2.*
FROM tbl t1
JOIN tbl t2 ON t2.id = ANY(t1.next)
OR t2.id = t1.id -- add first row
WHERE t1.id = 1 -- enter id to filter on once
ORDER BY (t2.id <> t1.id); -- "first row the data with ID = ?"
Should be fastest.
As #Daniel explained, this form (like your query) includes the first row only once.
If you want a "shorter query":
SELECT t2.*
FROM tbl t1
JOIN tbl t2 ON t2.id = ANY(t1.next || t1.id) -- append id to array
WHERE t1.id = 1; -- not sure if you need ORDER BY
Shorter, but not faster than the first form, because this will be expanded to an equivalent of the first form internally. Test performance with EXPLAIN ANALYZE.
It should be noted that next can even be NULL, because:
SELECT NULL::int[] || 5 --> '{5}'
This doesn't require recursion, just array un-nesting.
This should work:
select * from tablename where id=1
UNION ALL
select * from tablename where id
in (select unnest(next) from tablename where id=1);

SELECT query with cross rows WHERE statement

I'll try to explain the type of the query that I want:
Assume I have a table like this:
| ID | someID | Number |
|----|--------|--------|
| 1 | 1 | 10 |
| 2 | 1 | 11 |
| 3 | 1 | 14 |
| 4 | 2 | 10 |
| 5 | 2 | 13 |
Now, I want to find the someID that have a specific numbers (For example query for numbers 10, 11, 14 will return someID 1 and query for numbers 10, 13 will return 2). But, if someID contains all the query numbers but also more numbers, it will not return by the query. (For example query for 10, 11 will return nothing).
Is it possible?
SELECT t1.someId
FROM yourTable t1
WHERE t1.number IN (10,14,11)
GROUP BY t1.someID
HAVING COUNT(DISTINCT t1.ID) = (SELECT COUNT(DISTINCT t2.ID) FROM yourTable t2 WHERE t1.someID=t2.someID)
Example Fiddle
select someID
from yourtable
where number in (10,11,14)
and not exists (select * from yourtable t2 where number not in(10,11,14)
and t2.someid=yourtable.someid)
group by someID
having count(distinct ID) = 3
Where 3 is the number of items you are querying for
Yes, once you get the query numbers into a table variable (say it's called #QNums, with one column named QNum)) try
Select distinct someId
From table t
Where exists (Select * from #QNums
where QNum = t.Number)
And not Exists (Select * From table t2
Where someId = t.someId
And not exists(Select * From #QNums
where QNum = t3.Number))