I have a table in db for customers and their glasses
customer_inventory_tbl:
SELECT * FROM customer_inventory_tbl
+-------+-------+-------+
|id(pk) | name | spex |
+-------+-------+-------+
|1 |John |Oval |
|2 |Steve |Angular|
|3 |John |Aviator|
|4 |Kevin |Supra |
|5 |Jamie |Oval |
|6 |Ben |Supra |
+-------+-------+-------+
(this is a way more simplified version, haha)
If I view John's record it shows
SELECT * FROM customer_inventory_tbl WHERE name=John
+-------+-------+-------+
|id(pk) | name | spex |
+-------+-------+-------+
|1 |John |Oval |
|3 |John |Aviator|
+-------+-------+-------+
But what I require is when viewing John's record, it to show me
+-------+-------+-------+-----+
|id(pk) | name | spex |count|
+-------+-------+-------+-----+
|1 |John |Oval |2 |
|3 |John |Aviator|1 |
+-------+-------+-------+-----+
That "count" column is the number of records in the database that has "Oval" for instance.
Now that is easy enough, if I wanted to count every record in the db, but how do I get the count of all records whilst looking for a specific name.
I hope this makes sense
select c.*,
(
select count(1)
from customer_inventory_tbl
where spex = c.spex
) "count"
from customer_inventory_tbl c;
As a solution according to above mentioned description please try executing following sql query
SELECT *,(select count(id) from customer_inventory_tbl group by spex)
as count FROM customer_inventory_tbl WHERE name='John'
In above mentioned sql query counter value is being retrieved through subquery with records grouped according to values of spex column using GROUP BY clause.
In a phone system scenario i have 2 tables.
table1 is composed by: customer_id, call_duration, calldate, skip_billing .
table2 is composed by: customer_id, bonus_seconds.
table1 stores all the calls for all customers and table2 stores the bonus_seconds which represents free conversation time allowed for a defined customer(ie: for customer 1 the FIRST 40 cumulative seconds are free).
I have to write a query to update table1 according to the condition explained below:
set skip_billing within calls which are defined free in table2.
So I first need to group by customer_id and then iterate over the calls, incrementing a cumulative variable(cumsec) over call_duration and set skip_billing accordingly.
table1 example is:
|customer_id |billsec | skipbill|
|1 |12 | 0 |
|1 |10 | 0 |
|1 |15 | 0 |
|1 |8 | 0 | <--need to set 1 due to cumsec=45 for customer_id=1
|2 |12 | 0 | <--nop
|3 |12 | 0 | <--nop
|2 |12 | 0 | <--need to set 1 due to cumsec=24 for customer_id=2
|1 |12 | 0 | <--need to set 1 ....
|3 |15 | 0 | <--need to set 1 due to cumsec=27 for customer_id=3
|customer_id |bonus_seconds|
|1 |40 |
|2 |20 |
|3 |15 |
How I can write a query or procedure in SQL to achieve this behaviour?
Thank you so much
Assuming table has a primary key = id you can try:
SET SQL_SAFE_UPDATES=0;
update table table1
join (select id, sum(billsec) s from table
group by id having sum(billsec) < 1000) t1
on (t1.id = table1.id)
set table1.skipbill = 1
So let's say you have the following data representing employees within a company. Column one is their unique ID, column 2 is the ID of their supervisor, and column 3 represents whether or not the employee is over 21. (Y means they are over 21, N means they are not)
|Employee ID |Supervisor ID|Over21|
-----------------------------------
|1 |1 |Y |
|2 |1 |N |
|3 |1 |Y |
|4 |2 |Y |
|5 |2 |Y |
|6 |3 |N |
|7 |3 |N |
So, if I wanted to find the number of employees that are over 21, I could do that pretty easily with:
SELECT SUM(CASE WHEN [Over21] IS 'Y' THEN 1 ELSE 0 END)
But let's say you want to find the number of supervisors that have an employee that is over 21. (In this example it would be 2). I've been racking my brain trying to figure out a way to write out a way to find that but I've been struggling so far.
select count (distinct Supervisor)
from your_tab
where Over21 = 'Y';
Without where:
select count (distinct case when Over21 = 'Y' then Supervisor else null end)
from your_tab;
Problem description
I'm trying to get a comma-separated list of average grades for each recommendation, which consists of another comma-separated list of recommended content IDs. A recommendation is an object which consists of content that will receive the recommendation (ContentID) and a list of other contents that will be recommended (RecommendedContentIDs).
Table structure, sample data and other limitations
I have a two table database structure. The first table contains a recommended content IDs saved as a comma-separated ranked list. The second table contains grades for each of the recommended content IDs. The ranked lists have up to 10 comma-separated values and grades range from 0 to 5.
To better illustrate the problem, here are the table structures and some sample data:
Table Recommendations
|ID |ContentID |RecommendedContentIDs |Type |
+------+-------------+----------------------+-----+
|1 |2051 |9706,14801,13354,... |a |
+------+-------------+----------------------+-----+
|67 |2051 |8103,16366,8795,... |b |
+------+-------------+----------------------+-----+
|133 |2051 |8795,8070,15341,... |c |
+------+-------------+----------------------+-----+
|22 |1234 |4782,283,33,... |a |
+------+-------------+----------------------+-----+
...
Table Grades
|ID |RecommendationID |RecommendedDocumentID |Grade |EvaluatorHash|
+------+-----------------+----------------------+------+-------------+
|1 |1 |9706 |4 |123456789 |
+------+-----------------+----------------------+------+-------------+
|2 |1 |14801 |5 |123456789 |
+------+-----------------+----------------------+------+-------------+
|3 |1 |13354 |3 |987654321 |
+------+-----------------+----------------------+------+-------------+
|3 |1 |9706 |3 |987654321 |
+------+-----------------+----------------------+------+-------------+
|4 |67 |8103 |5 |123456789 |
+------+-----------------+----------------------+------+-------------+
|1 |67 |16366 |4 |987654321 |
+------+-----------------+----------------------+------+-------------+
|1 |133 |8795 |2 |123456789 |
+------+-----------------+----------------------+------+-------------+
...
I've transformed the RecommendedContentIDs column in table Recommendations into a separate table that looks like this:
Table RecommendedContent
|ID |RecommendationID |RecommendedContentID |Rank |
+------+-----------------+---------------------+-----+
|1 |1 |9706 |1 |
+------+-----------------+---------------------+-----+
|2 |1 |14801 |2 |
+------+-----------------+---------------------+-----+
|3 |1 |13354 |3 |
+------+-----------------+---------------------+-----+
|4 |1 |12787 |4 |
+------+-----------------+---------------------+-----+
...
+------+-----------------+---------------------+-----+
|11 |2 |19042 |1 |
+------+-----------------+---------------------+-----+
|12 |2 |13376 |2 |
+------+-----------------+---------------------+-----+
|13 |2 |9853 |3 |
+------+-----------------+---------------------+-----+
Expected result
I would now like to make a query that would return a result set that contains two comma-separated lists which are correspondent, so that I'll be able to display the average grade for each recommended content ID. It should look something like this:
|ContentID |RecommendedContentIDs |RecommendedContentAverageGrades |Type |
+-------------+-------------------------+----------------------------------+------+
|2051 |9706,14801,13354,... |3.5,5.0,3.0,... |a |
+-------------+-------------------------+----------------------------------+------+
|2051 |8103,16366,8795,... |5.0,4.0,0.0,... |b |
+-------------+-------------------------+----------------------------------+------+
|2051 |8795,8070,15341,... |2.0,0.0,0.0,... |c |
+-------------+-------------------------+----------------------------------+------+
...
As you can see, the RecommendedContentAverageGrades column contains the average grades for each corresponding ContentID in the column RecommendedContentIDs (Content with ID 9706 was graded twice, once with 4 and once with 3 therefore the average is 3.5). If the content hasn't been graded, the average grade should be 0. What is really important here is that the two comma-separated lists are correspondent, because the list in RecommendedContentIDs is a ranked list.
I would normally implement something like this in C#, but I was wondering whether it can be done with SQL. I was thinking of using GROUP_CONCAT but I wasn't able to get a proper result set. I would be very grateful if someone would provide a working SQL query for MySQL and/or T-SQL, but just suggestions will be fine too.
Edits
#1 - Laurence mentioned using separate tables instead of comma-separated lists. I'm using them due to an old design, which I cannot change. However, I am open to answers which assume that data in comma-separated lists is stored in separate tables.
#2 - Changed structure like Laurence suggested (using separated tables - see updated structure).
This just follows up the answer given by #Laurence:
http://sqlfiddle.com/#!2/7d236/6
Updated with Akrigg's fix and sql fiddle, also with how to order by values in the recommendation table
Also updated using order by in the group_concat clause as per brozo's fix:
Table RecommendedContent
+-----------------+----------------------+
|RecommendationID | RecommendedContentID |
+-----------------+----------------------+
| 1 | 9706 |
| 1 | 14801 |
| 1 | 13354 |
| 67 | 8103 |
| ... | ... |
+-----------------+----------------------+
Select
a.RecommendationID,
a.ContentID,
Group_Concat(a.RecommendedContentId Order By a.Rank),
Group_Concat(Trim(Trailing '.' From Trim(Trailing '0' From a.AverageGrade)) Order By a.Rank),
a.Type
From (
Select
r.RecommendationID,
r.ContentID,
r.Type,
rc.RecommendedContentID,
rc.Rank,
Coalesce(Avg(g.Grade), 0) As AverageGrade
From
Recommendations r
Left Outer Join
RecommendedContent rc
On r.RecommendationID = rc.RecommendationID
Left Outer Join
Grades g
On rc.RecommendedContentID = g.RecommendedDocumentID And
rc.RecommendationID = g.RecommendationID
Group By
r.RecommendationID,
r.ContentID,
r.Type,
rc.RecommendedContentID,
rc.Rank
) as a
Group By
a.RecommendationID,
a.ContentID,
a.Type
Order By
a.ContentID, -- Or other way round if that's what you prefer
a.RecommendationID
http://sqlfiddle.com/#!2/ca8b8/8
You could create a custom aggreate in sql server to do the comma separated string concatenation and then use it like this:
SELECT ContentID, RecommendedContentIDs, CustomToCsv(AvgGrade), Type FROM
(
SELECT ContentID, RecommendedContentIDs, AVG(Grade) AvgGrade, Type
FROM Recommendations r INNER JOIN Grades g ON r.ID = g.RecommendationID
GROUP BY ContentID, RecommendedContentIDs, RecommendedDocumentID, Type
) as t
GROUP BY ContentID, RecommendedContentIDs, Type
this is done in oracle
WITH count_number AS
(SELECT
ContentID,
','
||RecommendedContentIDs
||',' new_ContentIDs,
RecommendedContentIDs,
type ,
LENGTH(RECOMMENDEDCONTENTIDS )-LENGTH(REPLACE(RECOMMENDEDCONTENTIDS ,','))+1 COUNT_ID
FROM Recommendations
) ,
RecommendedContentIDs_postion AS
(SELECT A1.*,
B1.CONTENTIDS_OCCURANCE_POSITION ,
SUBSTR(new_ContentIDs,instr(new_ContentIDs,',',1,ContentIDs_OCCURANCE_POSITION)+1 , INSTR(new_ContentIDs,',',1,ContentIDs_OCCURANCE_POSITION+1)-instr(new_ContentIDs,',',1,ContentIDs_OCCURANCE_POSITION)-1) ContentIDs
FROM count_number a1,
(SELECT I ContentIDs_OCCURANCE_POSITION
FROM DUAL model dimension BY (1 i) measures (0 X) (X[FOR I
FROM 2 TO 1000 increment 1] = 0)
) b1
WHERE b1.ContentIDs_OCCURANCE_POSITION<=a1.count_id
)
SELECT
CONTENTID,
WM_CONCAT(CONTENTIDS) RECOMMENDEDCONTENTIDS ,
WM_CONCAT(GRADE) avg_grade_contentid ,
type
FROM RECOMMENDEDCONTENTIDS_POSTION RCI,
(SELECT RECOMMENDEDDOCUMENTID,
AVG(GRADE) GRADE
FROM Grades
GROUP BY RECOMMENDEDDOCUMENTID
) GRD
WHERE TRIM(RCI.CONTENTIDS)=TRIM(GRD.RECOMMENDEDDOCUMENTID)
GROUP BY
ContentID,
type;
I'm working on mysql and have two tables with the same schema:
preTrial
|id|accusedId|articleid|
------------------------
|1 | 1 | 1 |
|2 | 1 | 2 |
|3 | 1 | 3 |
|4 | 2 | 1 |
|5 | 2 | 2 |
trial
|id|accusedId|articleid|
------------------------
|1 | 1 | 1 |
|2 | 1 | 2 |
|3 | 2 | 1 |
|4 | 2 | 2 |
I want to get those accusedIds where all the articleIds of the first and the second tables are equal.
The above example should only return the accusedId 2, cause for accusedId 1 there is no articleId 3 in the second table.
I hope you understand what i mean. I'm currently writing my thesis in law, and the the time i was into sql is long gone by. Of course i already did some research, and tried several joins, but i was not able to find a solution. Hopefully you can help me.
Try something like this:
select a.accusedId , sum(a.accusedid) as cnt_a, sum(coalesce(b.accusedId, 0)) as cnt_b
from a left join b on a.accusedId = b.accusedId and a.articleId = b.articleId
group by accusedId
having cnt_a = cnt_b
I haven't even run that, so it might be a little off, but give it a lash. What it's doing is returning zeroes for a row in a not matched by b, so the HAVING clause will filter your grouped results to those where the article counts are equal.