Translation Inner Join in JQL - mysql

I have a problem with INNER JOIN in my JQL. What I want to do is to retrieve all Users that have rate one User Z with a mean of >= 2. Users have to answer 3 questions that will determine the final rate of this User Z. There is 2 tables, User and Score.
Table User Table Score
Id_user Id_score Id_rated Id_rater Id_question Score
1 1 1 3 1 1
2 2 1 3 2 0
3 3 1 3 3 1
4 1 2 1 0
5 1 2 2 0
6 1 2 3 0
I want as a result only User 2 for example.
This is the error when I translare my query to JQL :
[32, 184] The join association path is not a valid expression.
My query works well in MySQL Workbench
SELECT *
FROM User
INNER JOIN (
SELECT ID_RATER, (AVG(Score.score)*5) as AvgScore
FROM Score
WHERE ID_RATED=1751
AND (
SELECT (AVG(Score.score) * 3)
FROM Score)
GROUP BY ID_RATER
) TabAvg
ON TabAvg.AvgScore >= 2
AND USER.ID=TabAvg.ID_RATER
Translating to JQL :
String sql =
"SELECT U "
+ "FROM User U "
+ "INNER JOIN "
+ "("
+ "SELECT S.id_rater, (AVG(S.Score) * 3) AS AvgScore "
+ "FROM Score S "
+ "WHERE S.id_rated= :id_rated"
+ "AND "
+ "("
+ "SELECT (AVG(S2.score) * 3) "
+ "FROM Score S2"
+ ") "
+ "GROUP BY S.id_rater"
+ ") TabAvg "
+ "ON TabAvg.AvgScore >= 2 "
+ "AND U.id_user = TabAvg.id_rater";

Well, I still don't know what the problem with
EntityManager.createQuery(sql)
but to bypass this, I used
EntityManager.createNativeQuery(sql)
by just copy/paste my working sql into my code.

Related

MySQL: Get top 30 rows with the highest number of columns set

I've got a table with the following schema:
user_id | A | B | C | D | E | F | G | H | I | J | K | L | M
------------------------------------------------------------
3829 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1
The colums A-M have boolean values, which are obviously 0 or 1.
Is there a way, aside from looping through all the columns, to:
get the number of columns that are set to 1 for a specific user, as well as
get the top 30 (or n) users who have the most columns set to 1?
I have a fair amount of experience with php and MySQL but a query like this is puzzling me.
I'm envisioning something of this sort:
$statement = "SELECT * FROM my_table WHERE count(*) > 1 ORDER BY DESC LIMIT 30";
Any help would be great :)
you can also use plus(+) as sum
SELECT A + B + C + D + F + G + H + I + J + K + L + M AS total,user_id
FROM my_table
ORDER BY total
LIMIT 30
This could be accomplished using adding the booleans and a FROM sub-query select statement.
As bool is stored as a bit you can use sum to get a running total for each row.
With this data then get to top n results with the highest value.
Something like this:
SELECT * FROM (
SELECT *, A + B + C + D + E + F + G + H + I + J + K + L + M AS Total
FROM Table1
)
ORDER BY Total DESC
LIMIT 30;
Or if you do not want to use a sub-query you will have to use a group by due to the use of the aggregate SUM function.
UPDATE: As I am not using the SUM function any more the group by in the second function is not needed so I have removed that too.
Something like this:
SELECT *, A + B + C + D + E + F + G + H + I + J + K + L + M AS Total
FROM Table1
ORDER BY Total DESC
LIMIT 30;
The logic is simple you just have to sort the data in decreasing order of the sum of all the other numeric column and fetch the first 30. That will give you the Top 30. This is tricky, as there is no aggregation to be done, so using sum function here is not right. So your query is supposed to be:
SELECT *
FROM Table1
ORDER BY (A + B + C + D + F + G + H + I + J + K + L + M) DESC
LIMIT 30;
Here is an SQL Fiddle Demo

MySQL select user who less performed an action

I have the following table structures:
ACTIONS
+ userid + action +
+----------+----------+
USERS
+ id + name +
+----------+----------+
+ 1 + james +
+----------+----------+
+ 2 + john +
+----------+----------+
A data example:
ACTIONS
+ userid + action +
+----------+----------+
+ null + action1 +
+----------+----------+
+ 1 + action2 +
+----------+----------+
+ 1 + action3 +
+----------+----------+
+ 2 + action4 +
+----------+----------+
I need a SELECT query that will return the user who performed less actions.
If all fields are null (the first launch) or all equal (all users performed the same action), it can return 1 user (rand, asc, desc, it's the same).
///////////////////
EDIT
Based on the Richard Hamilton's reply, this query only works with users already in ACTIONS table. If one or more user_id are NULL or users are not in ACTIONS, doesn't select from USERS table
SELECT id FROM users
INNER JOIN actions ON users.id = actions.user_id
GROUP BY user_id
ORDER BY COUNT(user_id)
LIMIT 1;
You'll want to use GROUP BY. We can then ORDER BY the number of actions they performed.
To find the one with the lowest number, just use LIMIT 1
SELECT user_id FROM users
INNER JOIN data ON users.id = data.users_id
GROUP BY action
ORDER BY COUNT(action)
LIMIT 1;

Combine Multiple Query with one standart column

I using MySQL, I have 2 Query Select SQL, first Query will return Result A, and second will return Result B, so i want to combine that two Query Result, ID column of Result A and value_num of Result B become standard Column, and i don't think for use subselect because i have tried that and it will take long time effort in query process , how can i do this ?
Result A :
+------------+--------------+
+ ID + Name +
+------------+--------------+
+ 1 + Steve +
+ 2 + Mile +
+ 3 + Santo +
+ 4 + Del Piero +
+ 5 + Jack +
============================+
Result B :
+------------+--------------+
+ Valuenum + value +
+------------+--------------+
+ 1 + 20 +
+ 2 + 30 +
+ 6 + 44 +
+ 7 + 55 +
============================+
Combine Result A dan Result B, below is my expect output.
+------------+--------------+----------+
+ID_valuenum + Name + value +
+------------+--------------+----------+
+ 1 + Steve + 20 +
+ 2 + Mile + 30 +
+ 3 + Santo + Null +
+ 4 + Del Piero + Null +
+ 5 + Jack + Null +
+ 6 + Null + 44 +
+ 7 + Null + 55 +
============================+==========+
Thanks
select
ta.Id as ID_Valuenume
,ta.name
,tb.value
from TableA ta
left join TableB tb on ta.ID=tb.valuenum
union
select
tb.valuenum
,ta.name
,tb.value
from TableB tb
left join TableA ta on ta.ID=tb.valuenum
You have to use UNION for this :
select ra.ID as ID_valuenum,
ra.Name,rb.value from ResultA ra left join ResultB rb on ra.ID=rb.Valuenum
UNION
select rb.Valuenum,null as Name,rb.value from ResultB where rb.Valuenum not in
(select ID from ResultB)
->In first part you have to use Left Join so it will give you data
+------------+--------------+----------+
+ID_valuenum + Name + value +
+------------+--------------+----------+
+ 1 + Steve + 20 +
+ 2 + Mile + 30 +
+ 3 + Santo + Null +
+ 4 + Del Piero + Null +
+ 5 + Jack + Null +
->In second part its not required to use any join then it will give data:-
+ 6 + Null + 44 +
+ 7 + Null + 55 +

Return data from several tables in database

I need some help getting data from several tables.
This is the tables I have:
_______________ ______________ ___________ _______________ _____________
|_tblUsers____| |_tblAnswers__| |_tblAlt__| |_tblQuestion_| |_survey_____|
| userID | | answerAltID | | altID | | questID | | surveyID |
| username | | userID | | altText | | questText | | surveyName |
|_____________| |_____________| |_questID_| |_surveyID____| |____________|
TblUsers have a list of users in the system, tblAnswers have all answers that has been given from users, tlbAlt holds alternatives for a question, and tblQuestion has the questions. There is one more table called tblSurveys, but that's not needed here as the ID is mentioned in the tblQuestion.
This is what I have so far:
SELECT
tblQuestion.questText,
tblAlt.altText,
Count(tblAnswers.answerID) as answers_count,
(SELECT COUNT(answerID) FROM tblAnswers, tblAlt
WHERE tblAnswers.answerAltID = tblAlt.altID
AND tblAlt.questID = " & CInt(questionID) & ") as total_count
FROM tblAlt, tblQuestion
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
This returns rows like this:
| What is blablabla? | The answer is... | 2 (has answered) | 10 (total
answers) |
This unfortunately only returns all rows for one question. Is there a way to get all rows that is a part of same survey (based on surveyID)?
If want the output to be like this:
| What is blablabla? | The answer is... | 2 (has answered) | 10 (total
answers) | Name of Survey |
I want to return ALL alternatives (with how many answered, total answers, related question and survey).
Update:
This my input:
SELECT tblalternativ.altTekst, tblalternativ.altID, Count(tblsvar.svarAltID) as antSvar,
(SELECT COUNT(*) FROM tblsvar, tblalternativ
WHERE tblsvar.svarAltID = tblalternativ.altID
AND tblalternativ.altSpmID = " & CInt(lblQuestion.Tag) & ") as antTotal,
(SELECT Count(*) FROM tblalternativ WHERE altSpmID = " & CInt(lblQuestion.Tag) & ") as spmTotal
FROM(tblalternativ) LEFT JOIN tblsvar ON (tblalternativ.altId = tblsvar.svarAltID)
WHERE(tblalternativ.altSpmID = " & CInt(lblQuestion.Tag) & ")
GROUP BY tblalternativ.altTekst ORDER BY tblalternativ.altID ASC
My output:
altTekst altID antSvar antTotal spmTotal
Black 83 1 3 5
Green 84 1 3 5
Yellow 85 1 3 5
White 86 0 3 5
Pink 87 0 3 5
But this only show statistics for one question. I want to show for all questions in one survey. So I need to get all altTekst for that survey, question name, and ID of survey.
I want:
spmTekst altTekst altID antSvar antTotal spmTotal evalID
What is... Black 83 1 3 5 1
What is... Green 84 1 3 5 1
What is... Yellow 85 1 3 5 1
What is... White 86 0 3 5 1
What is... Pink 87 0 3 5 1
Who is.... The king 88 2 3 3 1
Who is.... The pope 89 0 3 3 1
Who is.... The president 90 1 3 3 1
Which.... Shoe 91 2 3 2 1
Which.... Hat 92 1 3 2 1
In other words, I want the statistics from all questions in same survey (based on evalID).
To return all questions, answer text, count ofusers with that answer, and total answers provided; per survey.
Select TQ.QuestText, tAlt.altText, count(*) as Answers_count, suM(mTemp.Cnt) as total_count
FROM tblQuestion tq
LEFT JOIN tblAlt talt on Talt.QuestID = TQ.QuestID
LEFT JOIN tblAnswers ta on ta.AnswerAltID = talt.AltID
LEFT JOIN tblUsers tu ON Ta.UserID = TU.UserID
LEFT join tblAnswers ta2 on ta2.answeraltId = talt.altID
LEFT JOIN
(SELECT COUNT(*) cnt, questID
FROM tblAnswers
INNER JOIN tblAlt on AltID = AnswerAltID
group by questID) mTemp
on mTemp.QuestID = talt.QuestID
WHERE tQ.SurveyID = 123 --Change this to your value
Group by TQ.QuestText, TAlt.AltText
It's just a bunch of left joins vs inner joins; and i abstracted out the counts for each table once so it should be faster instead of doing a sub select on each row. This way it does it once for all rows and is done.
Try this(Not at all optimized, just added the survey part to it):
SELECT tblQuestion.questText, tblAlt.altText,
Count(tblAnswers.answerAltID) AS answers_count,
(SELECT COUNT(answerAltID) FROM tblAnswers, tblAlt
WHERE tblAnswers.answerAltID = tblAlt.altID AND
tblAlt.questID = " & CInt(questionID) & ") as total_count,
survey.surveyName
FROM survey, tblQuestion, tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.answerAltID)
WHERE tblAlt.questID = " & CInt(questionID) & " AND
tblQuestion.surveyID = survey.surveyID
GROUP BY tblAlt.altText;
Edit: Try this then:
SELECT tblQuestion.questText AS spmTekst, tblAlt.altText AS altTekst,
tblAlt.altID,
Count(tblAnswers.answerAltID) AS antSvar,
COUNT(tblAlt.altID) AS antTotal,
COUNT(tblQuestion.questID) AS spmTotal,
survey.surveyID AS evalID
FROM tblQuestion
JOIN survey ON (survey.surveyID = tblQuestion.surveyID)
JOIN tblAlt ON (tblAlt.questID = tblQuestion.questID)
LEFT JOIN tblAnswers ON (tblAnswers.answerAltID = tblAlt.altID)
WHERE tblAlt.questID = " & CInt(questionID) & " AND -- what really is this? review this
survey.surveyID = '123' -- the value u want
GROUP BY tblAlt.altText
ORDER BY tblAnswers.answerAltID;

Select rows from a table where all values of an array exist

I have this query that retreives a list of id's + NAME:
$sql = "SELECT id FROM #__table1 ";
$sql .= " WHERE (";
foreach($explode_tags as $k=>$explode_tag) {
$sql .= "name = ".$db->Quote(trim($explode_tag));
if(($k+1) != count($explode_tags))
$sql .= " OR ";
}
$sql .= ")";
$db->setQuery($sql);
$results = $db->loadResultArray();
The result is an array like this:
keywordID | NAME
1 cat
2 dog
3 horse
Now I have this table2:
id | ItemID | keywordID
1 4 1
2 4 2
3 4 3
4 6 1
5 6 2
6 7 1
I want to find from table2 all ItemID's that have all keywordID's found in table1.
In the example above I want to return only itemID 4 that has all keywords (all 3 of them).
I am running this query but I am not getting results:
...
$query .= " AND i.id IN (SELECT itemID FROM #__table2 WHERE (";
foreach($results as $k=>$result) {
$query .= "keywordID = ".(int)$result;
if(($k+1) != count($results))
$query .= " AND ";
}
$query .= "))";
UPDATE
Sorry, I miss read your question. I've done simple test using this data:
id itemId keywordId
1 4 1
5 4 2
6 4 3
7 5 2
8 5 3
9 6 1
10 6 2
11 6 3
12 7 3
13 9 3
14 9 2
15 9 1
and using this query:
SELECT itemId, GROUP_CONCAT( keywordId ORDER BY keywordId ) AS crpcnct, COUNT( itemId )
FROM `temporary_table_123`
GROUP BY 1
HAVING crpcnct = '1,2,3'
I can get the value that you wanted:
itemId crpcnct count(itemId)
4 1,2,3 3
6 1,2,3 3
9 1,2,3 3
To achieve this, all you have to do is build the keywordID you want to use:
$keywordIds[] = $results['keywordId'];
and then sort accending
sort($keywordIds);
the last step is, supply this array into query:
SELECT itemId, GROUP_CONCAT( keywordId ORDER BY keywordId ) AS crpcnct, COUNT( itemId )
FROM `temporary_table_123`
GROUP BY 1
HAVING crpcnct = '" . implode(",", $keywordIds) . "'
There you have it.
SELECT ItemID FROM table2 WHERE keywordID IN (SELECT keywordID FROM table1)
This might work. I'll have to create local copies of your tables to see for sure, though.
$array_names = array();
foreach($explode_tags as $k=>$explode_tag){
$array_names[] = 'name = ' . $db->Quote(trim($explode_tag));
}
$sql = "SELECT ItemID FROM table_2 WHERE keywordID IN (SELECT keywordID FROM table_1 WHERE " . implode(' OR ', $array_names) .")";
$db->setQuery($sql);
$results = $db->loadResultArray();