Mysql Calculate Percentage Of Selected Rows - mysql

I'm sorry if my question irrelevant. Because I'm not expert of mysql.
I have surveys in my website. If someone votes my survey, i want to show survey results to the voter.
Here is the DB Structure;
surveys Table (Includes Survey Name Description and survey_id)
survey_choices Table (Includes Survey Chocies and related with survey_id to Surveys Table)
I'm trying to calculate only visible survey choices %percentage.
If i have only 1 survey, it's calculating correct results. But if i have more than 1 survey, mysql calculating whole survey_vote_count values of all table.
Here is my MySQL query;
SELECT
survey_vote_id, survey_vote_name, survey_vote_count, survey_id,
survey_vote_count * 100 / t.s AS survey_percentage
FROM survey_votes
CROSS JOIN (SELECT SUM(survey_vote_count) AS s FROM survey_votes) t
WHERE visibility = :visibility
AND survey_id = :surveyId
ORDER BY `survey_votes`.`order_id` ASC
How can i calculate for eg only survey_id = 1 and visibility = 1 %percentage = %100?
Any help will greatly appricated.

You should add the same condition to your cross join. At the moment, in your select you sum all survey_vote_count without the same where condition (visibility and survey_id.

Related

Comparing each colum in a row to every row in the database sql

I am building a bot that matches users based on a score they get, this score is taken from calculations done to data in a database on the request of the user.
I have only 1 table in that database and a few columns (user,age,genre,language,format,...etc).
What I want to do is, once the user clicks "find match" button on the chatbot, this user's data, which is already in the database will be compared to the other user's data in the same table and compare each column 1 by 1 of each row.
For example, the user's genre preference will be compared to each genre pref of the other users in each row of the table, when there is a match, 1 point is added, then language will be compared of each user and 1 point is given when there's a match. This will go to each column in each row and be compared with the user's. In the end, the users that has highest matching points will be recommended to this user.
What's the best way and approach to do that?
I am using nodejs and mysql database.
Thank you.
I see this as a self join and conditional expressions:
select t.*,
(t1.genre = t.genre) + (t1.language = t.language) + (t1.format = t.format) as score
from mytable t
inner join mytable t1 on t1.user <> t.user
where t1.user = ?
order by score desc
The question mark represents the id of the currently logged on user, for who you want to search matching users. The query brings all other users, and counts how many values they have in common over the table columns: each matching value increases the score by 1. Results are sorted by descending score.

Group by one field and then group the result by another field

I have a Query that Groups by a column which is needed so I get the result that I need, and then I need to return results which should be done by Grouping the previous results by another field.
So basically I have a Survey table,
sql = SELECT * FROM Survey S
WHERE S.UserId = 79
Group By S.SurveyNumber
Having SUM (S.Counter) <> 0 ORDER BY S.SubmittedDate DESC
This returns the Survey grouped by the Number, and then I need to Group the result by SurveyName and return the Last Submitted Survey for that SurveyName ( Max(submittedDate).
Can I achieve this in using one query ? If I have
GroupBy S.SurveyNumber, S.SurveyName
Then it will try to find that have BOTH of the columns same.
How do I do this ?
i think it works:
SELECT
S2.SurveyName
,SUM(S2.Count) as SurveyCount
FROM (
select
SUM(S.SurveyNumber) as Count
,S.SurveyName
FROM Survey S
where S.SurveyNumber <> 0
Group By S.SurveyNumber,S.SurveyName
) as S2
Group By S2.SurveyName
This is how I understand this:
Every survey belongs to one user. You want the survey of one particular user.
The table is actually not a Survey table (with one record representing a survey), but a kind of survey chronology table. There are multiple records per survey.
You must look at all records per survey in order to know whether its paid.
For each paid survey you want the last chronology record.
You have already shown how to check whether a survey is paid. Now select the last date for them (the maximum date). Based on this get the related records from the table.
select *
from survey
where (surveynumber, submitteddate) in
(
select surveynumber, max(submitteddate)
from survey
where userid = 79
group by surveynumber
having sum(counter) <> 0
);
I may be wrong though, because you make it sound like a survey number is somehow independent from the survey name. (One survey number with various names? The same survey name for multiple survey numbers?)
You would certaily benefit from a better data model with at least two separate tables for survey and survey details.

sql queries using group by

I have a quiz_tracking table (in mysql) that contains the ff fields:
subjectid - the id of the subject ( think of your subjects in school)
assessmentname - the name of the assessment ( think of it as exam or like chapter exams, the exams you found at the end of each chapter) found in each subject
questionid - the id of the question
userid - the id of the user who took the exam
attempt - attempt number
answer - answer given
score - score gained for this question
rownum - disregard this column, i only put in this one so its easier to point out which row numbers i am particularly interested in.
When the user takes a quiz, the records are recorded here. The assessments have different number of questions. For this example, first assessment has 3, second assessment has 3, third assessment has 1. The user can leave the quiz at the middle, in this case the answer column will be null since the quiz taker abandoned it.
I created a sql fiddle for the table and the data.
http://sqlfiddle.com/#!9/a41473/1
Basically, what I want to come up is I need to filter this data set and present a data set that only contains completed assessment attempts. Meaning, if the assessment has 3 questions and all these questions were answered (answer is not null) then that should be in the filtered data set.
The way I figured out how to determine if there was a complete assessments is via this sql:
select max(a.question_count) from (
select count(distinct qt.questionid) as 'question_count'
from quiz_tracking qt
where qt.subjectid=22380
and qt.assessmentname = 'first assessment'
and qt.userid in (555,121)
group by qt.attempt, qt.userid ) a )
I count all the question ids. Then i do a
having ( sum(if(answer is not null,1,0)) = result of above subquery.
The assumptions here are,
the subjectid is provided,
all the assessment names are provided
all the userids are provided.
In the sql fiddle,i can do it for 1 assessment (e.g. 'first assessment'), but what I need to do is to produce a filtered data set that contains all the assessments (first assessment, second assessment, third assessment). The expected result should be row numbers 1,2,3,4,5,6,12,13,14,15,16,17,21,22.
Simply join the main table to an aggregate derived table that calculates question count and answer count, then in outer query return when both are equal:
select z.*, q_cnt.question_count, q_cnt.answer_count
from quiz_tracking z
inner join
(select c.userid, c.subjectid, c.assessmentname, c.attempt,
count(distinct c.questionid) as 'question_count',
sum(if(c.answer is not null,1,0)) as 'answer_count'
from quiz_tracking c
group by c.userid, c.subjectid, c.assessmentname, c.attempt) q_cnt
on q_cnt.userid = z.userid
and q_cnt.subjectid = z.subjectid
and q_cnt.assessmentname = z.assessmentname
and q_cnt.attempt = z.attempt
where q_cnt.question_count = q_cnt.answer_count
SQL Fiddle DEMO

Finding the sum of a field in a linked table per group with additional search criteria

My actual tables are much more complex but here is a simplified example of the problem I am trying to work out.
Table contact: ContactID, ContactName, Pending
Table purchase: PurchaseID, ContactID, Amount, Pending, Date
Table contact_purchase_link: ContactID, PurchaseID (although it may seem like the link table is not necessary in this simplified example it is necessary in the large table schema)
Here is the query that I currently have:
SELECT DISTINCT contact.ContactID,
( SELECT SUM(Amount)
FROM purchase
WHERE purchase.ContactID = contact.ContactID
AND purchase.Pending = 0
) totalpurchase
FROM contact
INNER JOIN ( contact_purchase_link JOIN purchase
ON (contact_purchase_link.PurchaseID = purchase.PurchaseID
))
USING (ContactID)
WHERE purchase.Date > '2013-12-06' AND
AND contact.Pending =0
The problem is that I want the totalpurchase (the sum of the amount field) to be limited to the search criteria of the purchase table - meaning the query should only return the sum of the purchases after the specified date per contact. I think in order to use a group by clause the query would have to be based off the purchase table but I need the query to use the contact table so that all contacts are listed with their total purchase amounts and other relevant client data.
Is there any way to do this within one query?
To further clarify:
This query is being generated as part of a search engine. An example of why a query like this would be done is if a user wanted to generate a contact list of lastnames starting with A with purchases of a specific item or as in this example of purchases for a specific date. So that in general the query would have to generate a list of all contacts and their data (with possible search criteria on the type of contact such as all lastnames starting with 'A' etc.) and the query can also include search criteria on the purchase table such as the date of the purchase and whether the purchase was for specific items etc.
I am trying to add in the option to also list the sum of the purchases for the contact however that sum has to be limited to the search criteria for the purchase table as well and not the sum of all the contacts purchases.
If I understand your question correctly, you need to move the date comparison inside the first subquery:
SELECT DISTINCT contact.ContactID,
( SELECT SUM(Amount)
FROM purchase
WHERE purchase.ContactID = contact.ContactID
AND purchase.Pending = 0
AND purchase.Date > '2013-12-06'
) totalpurchase
FROM contact
INNER JOIN ( contact_purchase_link JOIN purchase
ON (contact_purchase_link.PurchaseID = purchase.PurchaseID
)
USING (ContactID)
WHERE purchase.Date > '2013-12-06'
AND contact.Pending =0
But the comments are right - I corrected a couple of what appears to be syntax errors, and I'm not sure about the join to contact_purchase_link. Improve your question and my answer will be less like guesswork.

mysql select problem

Hi were trying to perform a mysql select which isnt going to plan and hoping someone can shed some light on it.
we have estimated 10,000 plus listing records, a customer can have several listing records for different locations. we need to select all customer listings where at least one of the locations is equal to a specifield location.
so for example lets say customer 1 has a listing in sheffiled, doncaster, leeds, wakefield and customer 2 has listings in london and brighton.
Now I want to select all customer listings where one of the listings is for the area sheffield.
Id hope to get back the 4 rows for customer 1 because one of his listings is in sheffield.
for the sake of this example lets just presume the table consists of just customerId and LocationName
I need to select all customerIds where one of the locationNames = sheffield. So Id get 4 rows retruend with the cusotmer ID and the 4 locations
How do you write this query in mysql? Im guessing subselect but not too sure.
SELECT customerid FROM customers_location
WHERE customerid IN(SELECT DISTINCT customerid FROM customers_location WHERE LocationName = 'sheffield')
Something like:
SELECT * FROM CUST_TABLE WHERE CUST_ID IN (
SELECT DISTINCT CUST_ID FROM CUST_TABLE WHERE CUST_LOCN='Sheffield')
Note; The distinct clause may not be strictly necessary, not sure.
That would give you eg. 4 records for customer xyz who has one of their listing locations as Sheffield, which I think is what you're asking.