matching percentage with mysql - mysql

I have been trying to create an algorithm with MySQL that returns a list of users that matches an offer and the percentage of the matching. If the users matches the basic main criteria of the offer, they got 70% as a start then if they match some secondary criteria the matching percentage adds up by 2%.
I still don't know how to do it, if you have any idea please enlighten me. Thank you in advance
1. | User | | Offer |
2. |:--------| |:---------|
3. | city | | city-lis |
4. | age | | age-min |
5. | gender | | gender |
List item
if those criteria meets those users should get 70% as matching percentage than if they meet other criteria the percentage goes up

From what I can deduce from your question, this bit of pseudocode might help:
SELECT username,
68 +
((SELECT city = "example")*2) +
((SELECT gender = "m")*2) +
((SELECT age > 21)*2) AS score
FROM users
WHERE city = "example" OR gender="m" OR age > 21;
Explanation
I first select users that match any of the criteria, then I generate a score using subqueries. The (SELECT gender = "m") type subqueries will result in 1 if they are true (IE: if gender is m). I then multiply that by 2 to get the preferred score of '2'. If gender does not match 'm' the result will be 0. And 0 * 2 = 0. I start out with a score of 68 because you mentioned a starting score of 70 if any field matched. Because all rows in this result will match at least one of these, I substracted 2.
In MySQL you can use SELECT without defining a table to select from. The query SELECT 1+1 will result in 2. When you use these as subquery you can use the fields in the result for all kinds of tricks. I used them to generate a 1 or 0 for my score result.

Related

what is the execution order of group by and aggregation function in case statement in mysql?

Here is the SQL problem.
Table: Countries
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| country_id | int |
| country_name | varchar |
+---------------+---------+
country_id is the primary key for this table.
Each row of this table contains the ID and the name of one country.
Table: Weather
+---------------+------+
| Column Name | Type |
+---------------+------+
| country_id | int |
| weather_state | int |
| day | date |
+---------------+------+
(country_id, day) is the primary key for this table.
Each row of this table indicates the weather state in a country for one day.
Write an SQL query to find the type of weather in each country for November 2019.
The type of weather is:
Cold if the average weather_state is less than or equal 15,
Hot if the average weather_state is greater than or equal to 25, and
Warm otherwise.
Return result table in any order.
One of the MySQL solutions is as follows:
SELECT country_name, CASE WHEN AVG(weather_state) <= 15 THEN 'Cold' WHEN AVG(weather_state) >= 25 THEN 'Hot'
ELSE 'Warm'
END AS weather_type
FROM Weather w
JOIN Countries c
ON w.country_id = c.country_id
AND LEFT(w.day, 7) = '2019-11'
GROUP BY w.country_id
How does the "case when AVG(weather_state)" get executed, if the group by gets executed after the select statement?
How does the "case when AVG(weather_state)" get executed, if the group by gets executed after the select statement?
AVG(weather_state) computes the per-group average of column weather_state. It and other aggregate functions can be used in a select clause, from which you can conclude that the grouping defined by a group by clause must be visible in the context where the select clause is evaluated. In this sense, at least, group by gets executed before select. Pretty much everything else does too.
It is possible for an aggregate query to be identifiable only from the select clause. In such cases, the select clause needs to be parsed before it is known that grouping (all rows into a single group) is to be performed. This is the closest I can think of to the execution-order claim you asserted, but it is not at all well characterized as group by being executed after select.
MySQL's implementation details surely present a more complicated picture, but the fact remains that MySQL does provide correct SQL semantics in this regard. Therefore, even if you look at the details, they cannot reasonably be characterized as executing the group by after the select. Whoever told you that was wrong, or at least their lesson was very misleading, or else you misunderstood them.

Count twice if certain condition satisfies in mysql

I have a scenario where I need to display total number of attendees of an event. With the help of registration form I have already captured the details of people who are attending and my table looks like below.
ID | NAME | PHONE_NUMBER | IS_LIFE_PARTNER_ATTENDING
1 | ABC | 1234567890 | N
2 | PQR | 1234567891 | Y
3 | XYZ | 1234567892 | N
I can easily display number of registrations by using count(id). But while displaying number of attendees I have to consider as two attendees if registrant is coming with his/her partner. (identified by IS_LIFE_PARTNER_ATTEDNING column)
So, in the above case, the number of registrants are 3, but number of attendees are 4, because "PQR" is coming with his/her life partner.
How can we do this in mysql query?
You can use the following query:
SELECT
SUM( 1 + (IS_LIFE_PARTNER_ATTEDNING = 'Y')) AS totalAttendees
FROM your_table;
WORKING DEMO
Since boolean expression resolves into 0/1 in MySQL so that you can capitalize this in your case.
Note:
SUM(a=b) returns 1 only if a is equal to b otherwise it returns 0
Caution:
*Never underestimate these parentheses (IS_LIFE_PARTNER_ATTEDNING = 'Y'). If you omit them then the whole summation would result in zero(0).
* because of operator precedence
Use SUM with CASE
SELECT
Name,
SUM(CASE WHEN IS_LIFE_PARTNER_ATTEDNING='y' THEN 2 ELSE 1 END ) AS'Attendes'
FROM
table
GROUP by name

Fewest grouped by distinct - SQL

Ok, I think the answer of this is somewhere but I can't find it...
(and even my title is bad)
To be short, I want to get the fewest number of group I can make from a part of an association table
1st, Keep in mind this is already a result of a 5 table (+1k line) join with filter and grouping, that I'll have to run many time on a prod server as powerful as a banana...
2nd, This is a fake case that picture you my problem
After some Querying, I've got this data result :
+--------------------+
|id_course|id_teacher|
+--------------------+
| 6 | 1 |
| 6 | 4 |
| 6 | 14 |
| 33 | 1 |
| 33 | 4 |
| 34 | 1 |
| 34 | 4 |
| 34 | 10 |
+--------------------+
As you can see, I've got 3 courses, witch are teach by up to 3 teacher. I need to attend at one of every course, but I want as few different teacher as possible (I'm shy...).
My first query
Should answer : what is the smallest number of teacher I need to cover every unique course ?
With this data, it's a 1, cause Teacher 1 or Teacher 4 make courses for these 3 one.
Second query
Now that I've already get these courses, I want to go to two other courses, the 32 and the 50, with this schedule :
+--------------------+
|id_course|id_teacher|
+--------------------+
| 32 | 1 |
| 32 | 12 |
| 50 | 12 |
+--------------------+
My question is : For id_course N, will I have to get one more teacher ?
I want to check course by course, so "check for course 32", no need to check many at the same time
The best way I think is to count an inner join with a list of teacher of same fewest rank from the first query, so with our data we got only two : Teacher(1, 4).
For the Course 32, Teacher2 don't do this one, but as the Teacher1 do Courses(6, 33, 34, 32) I don't have to get another teacher.
For the Course 50, the only teacher to do it is the Teacher12, so I'll not find a match in my choice of teacher, and I'll have to get one more (so two in total with these data)
Here is a base [SQLFiddle
Best regards, Blag
You want to get a distinct count of ID_Teachers with the least count then... get a distinct count and limit the results to 1 record.
So perhaps something like...
SELECT count(Distinct ID_Teacher), Group_concat(ID_Teacher) as TeachersIDs
FROM Table
WHERE ID_Course in ('Your List')
ORDER BY count(Distinct ID_Teacher) ASC Limit 1
However this will randomly select if a tie exists... so do you want to provide the option to select which group of teachers and classes should ties exist? Meaning there are multiple paths to fulfill all classes involving the same number of teachers... For example teachers A, B and A, C fulfill all required classes.... should both records return in the result or is 1 sufficient?
So I've finally found a way to do what I want !
For the first query, as my underlying real need was "is there a single teacher to do everything", I've lower a bit my expectation and go for this one (58 lines on my true case u_u") :
SELECT
(
SELECT count(s.id_teacher) nb
FROM t AS m
INNER JOIN t AS s
ON m.id_teacher = s.id_teacher
GROUP BY m.id_course, m.id_teacher
ORDER BY nb DESC
LIMIT 1
) AS nbMaxBySingleTeacher,
(
SELECT COUNT(DISTINCT id_course) nb
FROM t
) AS nbTotalCourseToDo
[SQLFiddle
And I get back two value that answer my question "is one teacher enough ?"
+--------------------------------------+
|nbMaxBySingleTeacher|nbTotalCourseToDo|
+--------------------------------------+
| 4 | 5 |
+--------------------------------------+
The 2nd query use the schedule of new course, and take the id of one I want to check. It should tell me if I need to get one more teacher, or if it's ok with my actual(s) one.
SELECT COUNT(*) nb
FROM (
SELECT
z.id_teacher
FROM z
WHERE
z.id_course = 50
) t1
WHERE
FIND_IN_SET(t1.id_teacher, (
SELECT GROUP_CONCAT(t2.id_teacher) lst
FROM (
SELECT DISTINCT COUNT(s.id_teacher) nb, m.id_teacher
FROM t AS m
INNER JOIN t AS s
ON m.id_teacher = s.id_teacher
GROUP BY m.id_course, m.id_teacher
ORDER BY nb DESC
) t2
GROUP BY t2.nb
ORDER BY nb DESC
LIMIT 1
));
[SQLFiddle
This tell me the number of teacher that are able to teach the courses I already have AND the new one I want. So if it's over zero, then I don't need a new teacher :
+--+
|nb|
+--+
|1 |
+--+

SQL data query request

I'd appreciate your help with an SQL problem.
I have some student quiz score data in an SQL table and I wish to write a query to extract the information that I want. Candidates can attempt the tests as many times as they wish. Ideally, for each candidate, I wish to find out their highest percentage score on each of the tests. And I wish to get an average percentage of their highest percentage score on each test. Many of the candidates will not have done all of the tests. For example, candidate 1's highest scores on tests 1, 2 and 3 are 50%, 100% and 0%, leaving an overall average of 50%.
The table is named resultsets. The relevant column titles names are: Candidate (this is the student ID number), QuizName (the title of each quiz), and PercentageScore. It looks like this:
Candidate | QuizName | PercentageScore
---------------------------------------
1 | Test1 | 25
1 | Test1 | 50
1 | Test2 | 100
1 | Test3 | 0
2 | Test1 | 50
2 | Test1 | 100
3 | Test3 | 75
I'm hoping to get a table that looks something like this:
Candidate | Test1 | Test 2 | Test 3 | AveragePercentageScore
---------------------------------------
1 | 50 | 100 | 0 | 50
2 | 50 | 100 | 0 | 50
3 | 0 | 0 | 75 | 25
(Thanks Jain) I'd like to know the SQL command that I should enter.
Thank you!
Aside from being a beginner, it would be good to get a handle on basic table / database structures, relationships, use of primary / foreign keys and especially data normalization.
As for learning queries, I have seen other people utilize SQL Zoo as it has sample data and covers samples of how to look for certain things that require different query, joins, left-joins, aggregates etc.
All that said, sometimes it makes things easier if you can understand queries based on YOUR data, not some generic sample database that you have no context on its application to your data.
With all that said, I will help you get started. You need aggregates (min, max, avg, count) that are typically applicable based on a "GROUP BY" column(s). In this first case, you want to find "for each candidate" (the group by), and each "QUIZ" for that CANDIDATE (also part of group by), you want the highest test.
SELECT
Q.candidate,
Q.quizname,
MAX( Q.PercentageScore ) as HighestScore
from
YourQuizTable Q
group by
Q.candidate,
Q.quizname
Will result in the following.
Candidate QuizName HighestScore
1 Test1 50
1 Test2 100
1 Test3 0 (a legit score on file)
2 Test1 100
3 Test3 75
From that, you could create a pivot. Now, different sql engines have different pivot syntax, but to better see on these specific quizes posted, I will be doing a hard-coded pivot. Since the pivot is derived (uses the first query as the basis), the first query IS the basis of the pivot.
SELECT
smry.Candidate,
if( smry.quizname = 'Test1', smry.HighestScore, 0 ) as HiTest1,
if( smry.quizname = 'Test2', smry.HighestScore, 0 ) as HiTest2,
if( smry.quizname = 'Test3', smry.HighestScore, 0 ) as HiTest3,
AVG( smry.HighestScore ) as AvgTest
from
( SELECT
Q.candidate,
Q.quizname,
MAX( Q.PercentageScore ) as HighestScore
from
YourQuizTable Q
group by
Q.candidate,
Q.quizname ) smry
group by
smry.Candidate
The "IF()" is applied as each row is attempted, and each row will only ever have an instance of 1 quizname, it would only be either "Test1", "Test2" or "Test3". IF it IS that proper test, then grab the highest score as the basis to show in that column result. The last column is a simple average.
The final group by is now keeping them per candidate, but this time WITHOUT the group of the quiz as the inner query had.

Microsoft Access 2003 Query - Count records and sum it

I'm creating a query with Microsoft Access 2003 and had encounter an issue. I'm new!
I've got 2 tables. First table, i have a list of records that include the name, property name and the country state. Second table, i have a list of property names, the number of units in the property and the property's country state.
I will like to count the number of records in the first table by its state, meanwhile summing up the number of units the property has in the state.
What I encountered is, when I sum the number of units, the units repeats!
Taking for example;
Table1:
Name | State | Property Name
Mr 1 | State A | Building AAA
Mr 2 | State A | Building AAA
Mr 3 | State A | Building BBB
Mr 4 | State B | Building XXX
Mr 5 | State B | Building XXX
Table2:
Property Name | State | Number of Units
Building AAA | State A | 100
Building BBB | State A | 50
Building XXX | State B | 20
My Result:
State | Number of Units | No of Records
State A | 250 | 3
State B | 40 | 2
The result i want:
State | Number of Units | No of Records
State A | 150 | 3
State B | 20 | 2
EXPANDED
Assuming you are using the Access query builder, you will need to construct three Select queries:
1) Table1 will be the source table for the first query. Use the State field twice in the query, first as a Group By field and second as a Count field. (Any of the fields could have been used for the count, since you are only interested in the number of records.) Save the query for use in the third query.
2) Table2 will be the source table for the second query. Use the State field as a Group By field and the Units field as a Sum field. Save this query, too.
3) The third query will bring the information together. For the source, use the first and second queries, with a join between them on the State field. Select the State field (from either query) as a Group By Field, the CountOfState field from the first query as a Sum field, and the SumofUnits field from the second query as a Sum field.
While the actual amount of work done by Access in producing the final result will not change, the three queries can be consolidated into a single query by editing the underlying SQL.
The new query was produced by inserting the Table1 and Table2 queries into the third, final result query, one on either side of the INNER JOIN statement. The T1 and T1 in the new query are aliases for the embedded queries that eliminate ambiguity in referencing the fields of those queries.
The new query cannot be created using the Query Builder (although the original three queries provide the raw material for it). Instead, the SQL must be written/pasted in/edited in the SQL View of the Query Builder.
SELECT T1.State AS State,
Sum(T1.CountOfState) AS Records,
Sum(T2.SumOfUnits) AS Units
FROM
(SELECT Table1.State,
Count(Table1.State) AS CountOfState
FROM Table1
GROUP BY Table1.State) T1
INNER JOIN
(SELECT Table2.State,
Sum(Table2.Units) AS SumOfUnits
FROM Table2
GROUP BY Table2.State) T2
ON T1.State = T2.State
GROUP BY T1.State;