Introducing a simple count subquery to an already existing subquery - sql

I am creating a simple image browser which is connected to an SQLite database. Within the browser, similar images are grouped into an event and each image is labelled with a few tags.
Someone helped me construct this very helpful query below. It contains 5 random tags as an example:
SELECT *
FROM
(SELECT
t.EventId,
SUM(CASE WHEN name = 'necktie' THEN 1 ELSE 0 END) as 'necktie',
SUM(CASE WHEN name = 'shirt' THEN 1 ELSE 0 END) as 'shirt',
SUM(CASE WHEN name = 'suit' THEN 1 ELSE 0 END) as 'suit',
SUM(CASE WHEN name = 'man' THEN 1 ELSE 0 END) as 'man',
SUM(CASE WHEN name = 'male' THEN 1 ELSE 0 END) as 'male'
FROM
TagsMSCV t
WHERE
name IN ('necktie', 'shirt', 'suit', 'man', 'male')
GROUP BY
t.EventId)
ORDER BY
COUNT(*) DESC
This returns how many of each tag (column is called 'name') show up in each event. However now I also need the size of the event (number of unique image id's in the event) which can be accomplished with the below query:
SELECT EventId, COUNT(DISTINCT ImageId)
FROM TagsMSCV
GROUP BY EventId
But I have no idea how to introduce this syntax into the subquery above? If I put it beside t.EventId, it only counts the image id's in event that are tagged with the 5 random tags which is not correct. I need the total unique image id's in the event.

First, your subquery is not necessary. Second, you can use conditional COUNT(DISTINCT):
SELECT t.EventId,
SUM(CASE WHEN name = 'necktie' THEN 1 ELSE 0 END) as necktie,
SUM(CASE WHEN name = 'shirt' THEN 1 ELSE 0 END) as shirt,
SUM(CASE WHEN name = 'suit' THEN 1 ELSE 0 END) as suit,
SUM(CASE WHEN name = 'man' THEN 1 ELSE 0 END) as man,
SUM(CASE WHEN name = 'male' THEN 1 ELSE 0 END) as male
COUNT(DISTINCT CASE WHEN name = 'necktie' THEN imageid END) as necktie_images,
COUNT(DISTINCT CASE WHEN name = 'shirt' THEN imageid END) as shirt_images,
COUNT(DISTINCT CASE WHEN name = 'suit' THEN imageid END) as suit_images,
COUNT(DISTINCT CASE WHEN name = 'man' THEN imageid END) as man_images,
COUNT(DISTINCT CASE WHEN name = 'male' THEN imageid END) as male_images
FROM TagsMSCV t
WHERE name IN ('necktie', 'shirt', 'suit', 'man', 'male')
GROUP BY t.EventId
EDIT:
If you want the total distinct images for an event, then no conditional logic is needed. Just use:
COUNT(DISTINCT imageid) as total_images,
And remove the WHERE clause.

Related

GROUP BY SUM CASE expression

I want to group by account number, but I am running into problems if I get multiple RATE_CD's for an account - I get a NONCOMPLIANT_CNT of 2, but I want it to be only 1 per account even if there is more than 1 RATE_CD.
Below is the SQL I'm playing around with, any ideas on how I can return the NONCOMPLIANT_CNT per account, and not roll up the count if there is more than 1 RATE_CD?
SELECT ID
,ACCOUNT_NBR SUM(CASE
WHEN GROUP_CD = 'RED'
AND TYPE_CD IN ('CHK')
THEN 1
ELSE 0
END) AS 'COMPLIANT_CNT'
,SUM(CASE
WHEN GROUP_CD = 'RED'
AND TYPE_CD IN (
'CN'
,'RN'
)
AND RATE_CD <> 'BLK'
THEN 1
ELSE 0
END) AS 'NONCOMPLIANT_CNT'
,SUM(CASE
WHEN GROUP_CD = 'RED'
AND TYPE_CD IN (
'CN'
,'RN'
,'CHK'
)
THEN 1
ELSE 0
END) AS 'TOTAL_CNT'
FROM DETAIL
LEFT OUTER JOIN RATE_LOOKUP ACCOUNT_NBR = ACCOUNT_NBR
GROUP BY ID
,ACCOUNT_NBR
,RATE_CD
If you only want 1 instead of how many actual, change your SUM() to MAX(). So if they have 5 entries, it would still show as at least 1, otherwise will be 0 for the given column aggregate.

Need to create a Totals report from oracle table data

I have a table in oracle similar to the the example table image that I need to have output the segregated totals as shown in the second example results image.
I need the sums of each item_type where A & B are just examples for a large number of possible items that can be added.
example table:
example results:
Any help would be appreciated. thanks
Use conditional aggregation:
SELECT
store,
SUM(CASE WHEN item_type = 'A' AND item_status = 'IN' THEN 1 ELSE 0 END) a_items_in,
SUM(CASE WHEN item_type = 'A' AND item_status = 'OUT' THEN 1 ELSE 0 END) a_items_out,
SUM(CASE WHEN item_type = 'B' AND item_status = 'IN' THEN 1 ELSE 0 END) b_items_in,
SUM(CASE WHEN item_type = 'B' AND item_status = 'OUT' THEN 1 ELSE 0 END) b_items_out
FROM mytable
GROUP BY store

What does a multiple count query in SQL return?

I have a product table and every product might be delivered, idle, shipping, preparing.
I want to show a list with the counts of products for each state, and I can see how to query for that here:
How to get multiple counts with one SQL query?
However, what does this query return, and how do I assign the return value to lets say, 4 integers, called deliveredCount, idleCount, shippingCount, preparingCount?
PS: For the record, I am using SQLite with OrmLite in Android with JAVA
EDIT: In this SO question people explain what Query to do when you want to get multiple counts, but they don't tell us what does that query return and in what format. For example:
SELECT a.distributor_id,
(SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
(SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
(SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
FROM myTable a ;
What is the return type of this and what is the format?
PS2: Someone was really quick to downvote my question because it lacked sufficient information. Then I edited it, but the downvote still remains :(
Hard to say for sure but sounds like you need to use a version of the top answer in the link you have provided.
Something like;
SELECT ProductID,
COUNT(*) AS Total,
SUM(CASE WHEN pStatus = 'delivered' THEN 1 ELSE 0 END) DeliveredCount,
SUM(CASE WHEN pStatus = 'idle' THEN 1 ELSE 0 END) IdleCount,
SUM(CASE WHEN pStatus = 'shipping' THEN 1 ELSE 0 END) ShippingCount,
SUM(CASE WHEN pStatus = 'preparing' THEN 1 ELSE 0 END) PreparingCount
FROM ProductTable
GROUP BY ProductID
This will return something like;
ProductID | DeliveredCount | IdleCount | ...
1 | 250 | 3250 | ...
You might want to try this.
SELECT
SUM(CASE WHEN Prod = 'delivered' THEN 1 ELSE 0 END) as deliveredCount,
SUM(CASE WHEN Prod = 'idle' THEN 1 ELSE 0 END) as idleCount,
SUM(CASE WHEN Prod = 'shipping' THEN 1 ELSE 0 END) as shippingCount,
SUM(CASE WHEN Prod = 'preparing' THEN 1 ELSE 0 END) as preparingCount
FROM Product
select
concat(state, "Count"),
count(*)
from product
group by state
Which would return 4 rows (assuming four unique values of state):
fooCount | 15
etc

methods to separate multiple count(*)s by external field

I didn't know exactly what to call this question, so apologies if the title is confusing. I'm trying to generate a summary of user activity for a particular website. This query returns the total number of hits per type of page:
select
count(case when internal_handle = 'content' then 1 else null end) as CONTENT,
count(case when data = '/webapps/assessment/take/launch.jsp' then 1 else null end) as ASSESSMENTS,
count(case when internal_handle = 'discussion_board_entry' then 1 else null end) as DISCUSSIONS,
count(case when data = '/webapps/blackboard/execute/uploadAssignment' then 1 else null end) as BB_ASSIGNMENTS,
count(case when data = '/webapps/turn-plgnhndl-BBLEARN/links/submit.jsp' then 1 else null end) as TII_ASSIGNMENTS,
count(case when data = '/webapps/osv-kaltura-BBLEARN/jsp/courseGallery.jsp' then 1 else null end) as COURSE_GALLERY,
count(case when data = '/webapps/osc-BasicLTI-BBLEARN/frame.jsp' then 1 else null end) as ECHO_360,
count(case when internal_handle = 'check_grade' then 1 else null end) as MY_GRADES
from BBLEARN.ACTIVITY_ACCUMULATOR
where course_pk1 = (select pk1 from BBLEARN.course_main where course_id = '2014FA.BOS.PPB.445.A')
and user_pk1 in (select users_pk1 from BBLEARN.course_users where role = 'S' and crsmain_pk1 = course_pk1);
So the result is like:
CONTENT,ASSESSMENTS,DISCUSSIONS,BB_ASSIGNMENTS,TII_ASSIGNMENTS,COURSE_GALLERY,ECHO_360,MY_GRADES
5787,954,335,0,0,0,837,222
My goal, though, is to have it separated by hits per user. For instance, I'd want a result like:
USER_PK1,CONTENT,ASSESSMENTS,DISCUSSIONS,BB_ASSIGNMENTS,TII_ASSIGNMENTS,COURSE_GALLERY,ECHO_360,MY_GRADES
USER_A,250,79,41,0,0,0,66,7
USER_B,144,89,82,0,0,0,24,0
USER_C,174,45,23,0,0,0,58,1
--etcetera
I can imagine running the above query iteratively, but I'm not familiar enough with Oracle to do it effectively. How might I go about doing this? Or is there a better way to get the fields I'm looking for?
Thanks in advance!
Just add a group by:
select user_pk1,
count(case when internal_handle = 'content' then 1 else null end) as CONTENT,
count(case when data = '/webapps/assessment/take/launch.jsp' then 1 else null end) as ASSESSMENTS,
count(case when internal_handle = 'discussion_board_entry' then 1 else null end) as DISCUSSIONS,
count(case when data = '/webapps/blackboard/execute/uploadAssignment' then 1 else null end) as BB_ASSIGNMENTS,
count(case when data = '/webapps/turn-plgnhndl-BBLEARN/links/submit.jsp' then 1 else null end) as TII_ASSIGNMENTS,
count(case when data = '/webapps/osv-kaltura-BBLEARN/jsp/courseGallery.jsp' then 1 else null end) as COURSE_GALLERY,
count(case when data = '/webapps/osc-BasicLTI-BBLEARN/frame.jsp' then 1 else null end) as ECHO_360,
count(case when internal_handle = 'check_grade' then 1 else null end) as MY_GRADES
from BBLEARN.ACTIVITY_ACCUMULATOR
where course_pk1 = (select pk1 from BBLEARN.course_main where course_id = '2014FA.BOS.PPB.445.A') and
user_pk1 in (select users_pk1 from BBLEARN.course_users where role = 'S' and crsmain_pk1 = course_pk1)
group by user_pk1;
If user_pk1 isn't what you mean by "user", then you might have to join in another table.

Optimally querying a database of ratings?

I have a table of ratings that stores a user ID, object ID, and a score (+1 or -1). Now, when I want to display a list of objects with their total scores, the number of +1 votes, and the number of -1 votes.
How can I do this efficiently without having to do SELECT COUNT(*) FROM rating WHERE (score = +/-1 AND object_id = ..)? That's two queries per object displayed, which is unacceptable. Is the database design reasonable?
While it doesn't address your question of reasonable design, here's a query that gets you both counts at once:
select
sum(case when score = 1 then 1 else 0 end) 'positive'
, sum(case when score = -1 then 1 else 0 end) 'negative'
, objectId
from
ratings
where
objectId = #objectId ...
group by
objectId
This should do it:
SELECT
UserID, ObjectID,
SUM(CASE WHEN score=1 Then 1 Else 0 End) as UpVotes,
SUM(CASE WHEN score=-1 Then 1 Else 0 End) as DownVotes,
FROM YourTable
GROUP BY UserID, ObjectID
select object_id,
sum(case when score = 1 then 1 else 0) upvotes,
sum(case when score = -1 then -1 else 0) downvotes,
sum(score)
from ratings
group by object_id
Perhaps something like that.