Retrieve a record that has 2 specific features in SQL - sql

I have the following database of pictures (a picture can have multiple features):
Table Picture
-------------
ID Name
1 Mona Lisa
2 Scream
Table Features
-------------
ID Name PictureID (FK to Picture)
1 Portrait 2
2 Expressive 2
3 Big 2
4 Small 1
5 Expressive 1
5 Big 1
I'd wish to do a query that retrieves all the Pictures that are a Portrait AND Big, (so the result would be in this case "Scream"). I've come up with this query to retrieve it, but I'm not sure if it is the prettiest and most efficient way to do it. Here's my proposal:
SELECT *
FROM Picture o
WHERE
(select count(*)
from Feature c
where o.id = c.pictureID and c.Name like '%Portrait%') >= 1
AND
(select count(*)
from Feature c
where o.id = c.pictureID and c.Name like '%Big%') >= 1
In this case, I have to go through the Features table twice (which, to my personal taste, I find it "ugly").
Thanks and regards

SELECT picture.name FROM picture
JOIN features
on picture.id=features.pictureID
WHERE features.name IN('Portrait','Big')
GROUP BY features.pictureID
HAVING COUNT(DISTINCT features.ID)>=2

Related

Getting ranges of arbitrary strings in SQL based on sequence dictated in a separate table

Consider the following dataset (may look weird but want to land my point that the strings are arbitrary):
Table A
TicketId
StartAnimal
EndAnimal
1
Monkey
Bee
1
Lion
Buffalo
Table B
Animal
Sequence
Monkey
1
Zebra
2
Bee
3
Turtle
4
Lion
5
Buffalo
6
Is it possible to retrieve the animals that correspond to Ticket ID 1 based on the different "ranges" in each of its rows? For example,for Ticket ID 1 the following animals should be retrieved: Monkey, Zebra, Bee, Lion, Buffalo.
As you can see the animal strings themselves have no order logic to it, but the sequence can be leveraged for it. I'm just failing to come up with how to reference it for each row in a single query.
Edit
As an edge case, sometimes the EndAnimal might not even have a sequence to start with, in which case only the StartAnimal should be returned. As an example, assuming Bee is not in the sequence table, we should only get Monkey, Lion and Buffalo. Is that something SQL can handle?
Thanks!
There are numerous ways, one such way is to inner join the tables to find the corresponding start and end sequences and then find those rows that qualify:
with s as (
select bs.Sequence s1, IsNull(be.sequence,1) s2, a.ticketId
from a left join b bs on bs.animal = a.StartAnimal
left join b be on be.Animal = a.EndAnimal
)
select b.Animal
from b
join s on b.Sequence >=s1 and b.Sequence <= s2
where s.ticketId = 1
order by b.Sequence;
Example Fiddle

Return count id's value from multiple rows in one column Postgres

I'm having two tables (relation between themTest_case.id = Test_tag.test_id) like this:
Test_case table
id
name
1
Test name 1
2
Test name 2
3
Test name 3
4
Test name 4
Test_tag table
test_id
tag
1
feature:example1
1
package:Reports
1
QA
2
feature:example1
2
package:Reports
2
QA
3
feature:example1
3
package:Reports
3
QA
4
feature:newexample1
4
package:Charts
4
QA
The database tables and structure were already defined as I'm using a oublic library to push the results.
So, I need to return in the result the count of the id's and the value feature:example1
knowing that is a test that contains the tag package:Reports
So, it should return something like
Results
count(id)
tag
3
feature:example1
I already tried some different approaches without success.
How can I do that?
I think I'm as confused as everyone else, but this is a shot in the dark based on the various comments. There are much easier ways to arrive at this dataset, but I'm trying to read between the lines on your comments:
select
count (t.test_id), t.tag
from
test_case c
join test_tag t on c.id = t.test_id
where
t.tag like 'feature%' and
exists (
select null
from test_tag t2
where t2.test_id = t.test_id and t2.tag = 'package:Reports'
)
group by
t.tag

Without using conjunctions in conditions of selection operators

Let's say there is a table call ITEM and it contains 3 attributes(name, id, price):
name id price
Apple 1 3
Orange 1 3
Banana 2 4
Cherry 3 5
Mango 1 3
How should I write a query to use a constants selection operator to select those item that have same prices and same ids ? The first thing come into my mind is use a rename operator to rename id to id', and price to price', then union it with the ITEM table, but since I need to select 2 tuples (price=price' & id=id') from the table, how can I select them without using the conjunctions operator in relational algebra ?
Thank you.
I'm not quite sure but for me, it would be something like this in relational calculus:
and then in SQL:
SELECT name FROM ITEM i WHERE
EXISTS ITEM u
AND u.name != i.name
AND u.price=i.price
AND u.id = i.id
But still, I think your assumption is right, you can still do it by renaming. I do believe it is a bit longer than what I did above.

Access SQL Syntax for Cross-Table Count

I have what may be a simple SQL syntax question but I've been scratching my head over it for weeks now and it's abstract enough that I'm having trouble hunting down the correct search in Google.
Let us assume that I have three tables: Users and Bookings:
Users:
UserID Name
1 Adam
2 Bob
3 Charlie
Bookings:
BookingID UserID MeetingID
1 1 1
2 2 1
3 2 2
4 3 2
The query that I'm looking to create will tell me how many other users each user has shared a meeting ID with. In my example:
Output:
UserID Co-Meeters
1 1
2 2
3 1
As in the example, users 1 and 3 only had one co-meeter (in this case "2") and user 2 had two co-meeters (1 and 3).
I'm sorry if my description isn't terribly clear, but I'm trying to strip out the needless complication from other intersecting tables and fields that don't really affect the syntax I'm looking for. My initial thought was to use "Group By", but since Bookings is a many-to-many (in terms of the fields I'm looking at) I can't make the logic work.
Any and all help is appreciated.
I think this should do the trick:
select u.userid, iif(isnull(x.others), 0, x.others) as [Co-Meeters]
from users u
left join bookings b on u.userid = b.userid
left join (
select meetingid, count(*) as others from bookings where userid <> u.userid
) x on b.meetingid = x.meetingid
order by 1

Why does this query return "incorrect" results?

I have 3 tables:
'CouponType' table:
AutoID Code Name
1 CouT001 SunCoupon
2 CouT002 GdFriCoupon
3 CouT003 1for1Coupon
'CouponIssued' table:
AutoID CouponNo CouponType_AutoID
1 Co001 1
2 Co002 1
3 Co003 1
4 Co004 2
5 Co005 2
6 Co006 2
'CouponUsed' table:
AutoID Coupon_AutoID
1 2
2 3
3 5
I am trying to join 3 tables together using this query below but apparently I am not getting right values for CouponIssued column:
select CouponType.AutoID, Code, Name, Count(CouponIssued.CouponType_AutoID), count(CouponUsed.Coupon_AutoID)
from (CouponType left join CouponIssued
on (CouponType.AutoID = CouponIssued.CouponType_AutoID))
left join CouponUsed
on (couponUsed.Coupon_AutoID = CouponIssued.AutoID)
group by CouponType.AutoID, code, name
order by code
The expected result should be like:
**Auto ID Code Name Issued used**
1 CouT001 SunCoupon 3 2
2 CouT002 GdFriCoupon 3 1
3 CouT003 1for1Coupon 0 0
Thanks!
SELECT t.AutoID
,t.Code
,t.Name
,count(i.CouponType_AutoID) AS issued
,count(u.Coupon_AutoID) AS used
FROM CouponType t
LEFT JOIN CouponIssued i ON i.CouponType_AutoID = t.AutoID
LEFT JOIN CouponUsed u ON u.Coupon_AutoID = i.AutoID
GROUP BY 1,2,3;
You might consider using less confusing names for your table columns. I have made very good experiences with using the same name for the same data across tables (as far as sensible).
In your example, AutoID is used for three different columns, two of which appear a second time in another table under a different name. This would still make sense if Coupon_AutoID was named CouponIssued_AutoID instead.
change count(Coupon.CouponType_AutoID) to count(CouponIssued.CouponType_AutoID) and count(Coupon.Coupon_AutoID) to count(CouponUsed.Coupon_AutoID)