Basically i have two tables. answers and choices . In my choices table, I got a column choices.value which is has values 0-4. My current query like this
$answers = \DB::table('answers')
->join('choices','answers.choice_id','=','choices.choice_id')
->select('answers.user_id','choices.choice_id','choices.choice','choices.value')
->where('answers.user_id',\Auth::user()->id)
//->groupBy('answers.user_id')
->get();
My current response is like this
"user_id": 2,
"choice_id": 2,
"choice": "I feel discourated about the future",
"value": 1
},
{
"user_id": 2,
"choice_id": 2,
"choice": "I don't enjoy things the way I used to",
"value": 1
},
{
"user_id": 2,
"choice_id": 2,
"choice": "I feel guilty a good part of time",
"value": 1
how do i add the values so that my result will be like this
"user_id":2,
"total_score":3
I tried doing DB::raw(SUM(choices.values)as score) but i get a large amount. I guess its adding all the choices values from the choices table and not in the answers.
My answers db which i only select the answers of the user = 2. I limit to 5
+---------+-------------+-----------+
| user_id | question_id | choice_id |
+---------+-------------+-----------+
| 2 | 1 | 2 |
| 2 | 2 | 2 |
| 2 | 3 | 2 |
| 2 | 4 | 2 |
| 2 | 5 | 2 |
+---------+-------------+-----------+
My choices table, I only select questions 1 and 2 and their choices.
+-----------+-------------+--------------------------------------------------------------+-------+
| choice_id | question_id | choice | value |
+-----------+-------------+--------------------------------------------------------------+-------+
| 1 | 1 | I do not feel sad | 0 |
| 2 | 1 | I feel sad | 1 |
| 3 | 1 | I am sad all the time and I can't snap out of it | 2 |
| 4 | 1 | I am so sad and unhappy that I can't stand it | 3 |
| 1 | 2 | I am not particularly discouraged about the future | 0 |
| 2 | 2 | I feel discourated about the future | 1 |
| 3 | 2 | I feel I have nothing to look forward to | 2 |
| 4 | 2 | I feel the future is hopeless and that things cannot improve | 3 |
+-----------+-------------+--------------------------------------------------------------+-------+
Also i want to make a new table named scores and the columns will be the result of what i want. I want to add the choices.values in the answer in every answers.user_id so that when i view the scores table, it will display the total score in every user or when the user finished answering all 21 questions because i only got 21 items it will automatically add in the scores table. Could I possibly do that?. Is it okay to add a value in the answers table based in the choice_id? That is what im thinking but I think its redundant since the choice_id is there already. Thanks in advance.
PS: Tried writing these queries but always get 441 which is the total value of all the choices in the choices table
SELECT answers.user_id,choices.choice_id,choices.value,COALESCE(sum(choices.value),0) as score FROM
`answers` JOIN `choices` ON choices.choice_id = answers.choice_id where
answers.user_id = 2
SELECT answers.user_id,choices.choice_id,choices.value,SUM(choices.value),0 as score FROM `answers`
join choices on choices.choice_id = answers.choice_id
where answers.user_id = 2
SELECT answers.user_id,choices.choice_id, sum(choices.value) from answers
JOIN `choices` ON choices.choice_id = answers.choice_id
group by answers.user_id
Currently you are only matching to a choice but you need to match the choice as well as the question.
I found this after seeng each choices.question_id had choices 1, 2, 3 and 4 in a slack conversation. I didn't know until I actually saw a screenshot of the choices table.
$answers = \DB::table('answers')
->join('choices', function ($q) {
$q->on('answers.choice_id','=','choices.choice_id')
->on('answers.question_id', '=', 'choices.question_id');
})
->select('answers.user_id',\DB::raw('sum(choices.value) as total'))
->groupBy('answers.user_id')
->get();
use group by maybe it will help
$answers = \DB::table('answers')
->join('choices','answers.choice_id','=','choices.choice_id')
->select('answers.user_id',DB::raw('count(*) as total'))
->where('answers.user_id',\Auth::user()->id)
->groupBy('answers.user_id')
->get();
Related
I'm having problems with getting correct data in a three-way join.
EDIT: Sample table structure
Jobs Table
id | name | country | country_slug | city
1 | Job1 | Canada | canada | Ontario
2 | Job2 | South Africa | south-africa | Durban
Cheers Table
id | rep | jobs_id
1 | 14 | 2
2 | 9 | 1
3 | 12 | 2
4 | 23 | 1
Categories Table
id | name
1 | PHP
2 | Laravel
3 | Javascript
4 | Go
category_job pivot Table
id | category_id | job_id
1 | 2 | 1
2 | 2 | 2
3 | 1 | 1
4 | 3 | 2
5 | 4 | 1
Here is an example of what my models look like:
Job
public function categories(){
$this->belongsToMany(Category::class)
}
public function cheers(){
$this->hasMany(Cheer::class)
}
Category
public function jobs() {
$this->belongsToMany(Job::class)
}
Cheer
public function job() {
return $this->belongsTo(Job::class);
}
This is what I'm trying to achieve:
Group jobs by country
Get count of how many jobs are in each country (job_count)
Get count how many cities (distinct) in each group (city_count)
Sum (rep) in cheers relation table for each group
Get the most popular category for each country group via Categories relationship
This is my code so far:
$result = Job::
selectRaw(
"jobs.country,
jobs.country_slug,
COUNT('jobs') as job_count,
COUNT(DISTINCT city) as city_count,
SUM(rep) as cheer_rep",
)
->join('cheers', 'cheers.jobs_id', '=', 'jobs.id')
->orderByDesc('cheer_rep')
->groupBy('jobs.country', 'jobs.country_slug')
->get();
Here are my problems;
The job count is wrong because the join clause adds more results due to the hasMany relationship.
I can't seem to wrap my head around grouping the categories and getting the most occurring (popular) category.
Sample result
[
{
"country": "Canada",
"country_slug": "canada",
"job_count": 23,
"cities": 5,
"cheer_rep": "35000"
},
{
"country": "South Africa",
"country_slug": "south-africa",
"job_count": 9,
"cities": 2,
"cheer_rep": "700"
},
]
Any help would be highly appreciated. Also, if there's an eloquent way of achieving this, I'd appreciate that too.
Eloquent way:
Job::with('cheers')
->select(DB::raw('count(country) as job_count, country'),
DB::raw('count(city) as city_count, city')
)
->orderByDesc('cheers.cheer_rep')
->groupBy('country', 'country_slug')
->get();
Note: Not tested, as you did not provided DB schema.
I have a table with multiple rows for each customer and and a visit_date. The visit date can be null as well.
My tables are as below:
customers:
id | name | email
1 | John Doe1 | a.b#gmail.com
2 | John Doe2 | b.c#gmail.com
3 | John Doe3 | x.y#gmail.com
store_customers
id | customer_id | store_id | email_optedin | visit_date
1 | 1 | 1 | 1 | 2015-11-30
2 | 1 | 2 | 1 | 2016-05-08
3 | 1 | 3 | 1 | null
4 | 2 | 1 | 1 | 2015-04-30
5 | 2 | 2 | 1 | 2015-08-40
6 | 2 | 3 | 1 | 2015-12-12
7 | 3 | 1 | 1 | null
8 | 3 | 2 | 1 | null
9 | 3 | 3 | 1 | null
I am trying to retrieve customers who either have not had a visit to the any of the three stores or have not visited since a specified date (e.g. 2016-04-15).
I am expecting customers 2 and 3 but not 1.
I tried this query:
select distinct * from customers
inner join store_customers on store_customers.customer_id = customers.id
where customers.email != '' and
store_customer.store_id in (1,2,3) and customers.emailStatus not in ('Unverified','Bounced','Spammed')
and
(
store_customer.email_optedin = 1
and max(store_customers.visit_date) <= '2016-04-15'
or account_customer.visit_date is null
);
This does not work. I somehow need to, for the set of store ids), I need to select customers who have either not had any visit (all nulls for visit date for the specified stores) or the if one or more visit dates are available then compare the max date to the specified date.
I found similar questions but none of the answers has worked for me, mainly because of the requirement of selecting either those customers who have no visit or if they do atleast one, then to compare the latest visit date from the set of stores in the joined table.
I am trying to do this all in one query but if that is not possible then I can break it up as well. I also do not want to change the order of joins because there are many other things added on to this query and changing the order of joins may become a problem.
I really appreciate any help that can be provided.
Regards,
Waqar
Try this query
SELECT
customers.id,
customers.name,
MAX(store_customers.visit_date)
FROM
customers LEFT JOIN store_customers on customers.id = store_customers.customer_id
GROUP BY customers.id,customers.name
HAVING MAX(store_customers.visit_date) < '2016-04-15' OR MAX(store_customers.visit_date) IS NULL
The query is supposed to do the following:
Obtain the question and associated answers based on the identification number of the question. (In this case the identification number is called account_id. Order them so that each question (and it's appropriate answers) are lined up in order.
The query:
SELECT *
FROM quiz_questions q
JOIN quiz_answers a
ON q.account_id = a.account_id
WHERE q.account_id = 1840979156127491
ORDER BY q.question_id
ASC LIMIT 5
The quiz_questions table and contents:
The quiz_answers table and contents:
Strange altered results:
As you can see where the question_id is ordered, all of the values are 1 however, the other question_id field (These fields match if you look at the previous data) are representing two, like they should. Also, even though the question (with the id of 2) is displayed in the secondary question_id field, the text for the question still belongs to question 1: (do you like waffles) apposed to (do you like pancakes).
What is causing these results? Here's what the expected results should look like: (Ignoring duplicate fields).
+------------------+-------------+----------------------+-----------+----------------------+---------+
| account_id | question_id | question | answer_id | answer | correct |
+------------------+-------------+----------------------+-----------+----------------------+---------+
| 1840979156127491 | 1 | Do you like waffles | 1 | Yes i like waffles | 1 |
| 1840979156127491 | 1 | Do you like waffles | 5 | I kinda like waffles | 1 |
| 1840979156127491 | 1 | Do you like waffles | 6 | Not at all | 0 |
| 1840979156127491 | 2 | Do you like pancakes | 7 | Yes | 1 |
| 1840979156127491 | 2 | Do you like pancakes | 8 | No | 0 |
+------------------+-------------+----------------------+-----------+----------------------+---------+
You need to join by account_id and also question_id
SELECT * FROM `quiz_questions`
INNER JOIN `quiz_answers`
ON `quiz_questions`.`account_id` = `quiz_answers`.`account_id`
AND `quiz_questions`.`question_id` = `quiz_answers`.`question_id`
WHERE `quiz_questions`.`account_id` = '1840979156127491'
ORDER BY `quiz_questions`.`question_id`
ASC LIMIT 5
I got the following MySQL table:
+----+--------+------+
| id | answer | type |
+----+--------+------+
>| 1 | -1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
>| 4 | -1 | 2 |
| 5 | 4 | 2 |
| 6 | 4 | 1 |
>| 7 | -1 | 1 |
| 8 | 7 | 2 |
>| 9 | -1 | 2 |
>| 10 | -1 | 1 |
>| 11 | -1 | 2 |
+----+--------+------+
> = original comment
The entries with answer = -1 are the original comments.
The entries with answer != -1 are answers to the comment with the respective id.
Furthermore there are types of comments (in this case 1 or 2).
Now I want to retrieve the original comments (for a specified type and a specified limit) and their answers (type and limit do not matter). Further it would be great to group the result by the two types (again, only the original comment's type matters for grouping).
A query result for type=1 and limit=2 should look like that (not grouped yet):
+----+--------+------+
| id | answer | type |
+----+--------+------+
>| 1 | -1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
>| 7 | -1 | 1 |
| 8 | 7 | 2 |
+----+--------+------+
I have tried several kinds of queries for hours now, can I implement it without a procedure? What would the procedure look like?
I would appreciate your help a lot.
Use a subquery to get 2 original comments of type-1 first, then join the table again to get both original comments and responses.
select b.*
from (
select id
from answers
where type = 1 and answer = -1
limit 2) a
join answers b on a.id = b.id or a.id = b.answer;
fiddle
To select 2 original comments of each type, you'll need to use user-defined-variable to index each original comment. The following code indexes the first original comment as 1, the second one as 2, and so on, then resets to 1 when the type changes. Finally in the final where statement filter out indices greater than 2.
select b.*, a.idx
from (
select id, #idx:=if(#type=a.type,#idx+1,1) idx, #type:=a.type
from (select id, type from answers2 where answer is null order by type) a
join (select #type:=null, #idx:=null) b) a
join answers2 b on a.id = b.id or a.id = b.answer
where a.idx <= 2;
fiddle
Store it as a separate column or even a different table if you are worried about too much data duplication. You are overthinking it.
I here today with a question that has left me rather confused and puzzled. Perhaps someone out there could give me a bit of assistance.
I have three table as followed. Please note that they are simplified for this question.
//table_checks//
check_id |task_id| status
1 | 1 | Done
2 | 1 | Done
3 | 1 | Done
4 | 2 | Done
5 | 2 | Not Done
6 | 2 | Not Done
7 | 2 | Not Done
8 | 2 | Done
9 | 3 | Done
10 | 3 | Done
11 | 3 | Not Done
12 | 3 | Done
//table_user//
user_id | email | type
1 | a#a.com | IN
2 | b#b.com | IN
3 | c#c.com | EX
//table_chk_usr//
check_id |user_id
1 | 1
2 | 1
3 | 1
4 | 2
5 | 2
6 | 2
7 | 2
8 | 2
9 | 3
10 | 3
11 | 3
12 | 3
Here are three tables with its relation in the table_chk_usr table.
My question is how do I query and select rows of table_user with type 'IN' from table table_user where all of users assigned task_ids in the table_checks are with the status = done.
So the expected result should be as follows
//table_user//
user_id | email | type
1 | a#a.com | IN
Since user_id with 1 has completed all task_ids with status done.
I hope this makes sense to those of you who are reading. Any help will be much appreciated.
Please Note that I am using PHP as my server side language, if that helps in any way.
I think this is what you are looking for.
select user.user_id, user.email, user.type,
sum(if(status = 'done',1, 0)) as done, count(*) as checks
from checks
join chk_user on checks.check_id = chk_user.check_id
join user on chk_user.user_id = user.user_id
group by chk_user.user_id
having done = checks
sqlFiddle
You could use a join here, but there may be a better way to do it.
SELECT * FROM table_checks
INNER JOIN table_chk_usr
ON table_checks.check_id = table_chk_usr.check_id
INNER JOIN table_user
ON table_chk_usr.user_id = table_user.user_id
WHERE table_checks.status = 'Done'
AND table_user.type = 'IN'