I have been studying and learning PHP and MySQL and I have started a system that I'm developing for a friend's little school and to help me to improve my learning. I basically have in this case a table with the names of the students (tb_std) and another with the names of the teachers (tb_tch). The work is to distribute these students among the teachers in a new table, which is the way I think it will work better (tb_final).
I basically need each student to have a randomly chosen teacher so that the distribution is numerically even among the teachers.
In this example, I have 7 teachers and 44 students. Using SELECT query I did the operations to find out how many students would be for each teacher (add/division/mod), but how to make this draw to play in this new table I have no idea where to start.
1) Students (tb_std)
---------
id |std
1 | A1
2 | A2
3 | A3
(...)
44 | A44
2) Teachers (tb_tch)
--------
id |tch
--------
1 | T1
2 | T2
3 | T3
(...)
7 | T7
3) Final Combo (tb_final)
--------------------
id| student | teacher
--------------------
1 | A1 | T1
2 | A2 | T2
3 | A3 | T4
4 | A4 | T6
5 | A5 | T2
(...)
This is what I her in code until now:
<?php
session_start();
include_once("../conn/conexao.php");
$str_std="SELECT COUNT(*) as tstd FROM tb_std ";
$qry_std=mysqli_query($conn,$str_std);
while($res1=mysqli_fetch_assoc($qry_std)){
$v1 = $res1['tstd']; // 44 students
echo "Students: ".$res1['tstd']."<br>";
}
$str_tch="SELECT COUNT(*) as ttch FROM tb_tch ";
$qry_tch=mysqli_query($conn,$str_tch);
while($res2=mysqli_fetch_assoc($qry_tch)){
$v2 = $res2['ttch']; // 7 teachers
echo "Teachers ".$res2['ttch']."<br><br>";
}
$div = number_format($v1 / $v2);
$res = $v1 % $v2;
echo "Stud/Teach: ".$div."<br>"; // 6 std per teach
echo "Mod: ".$res."<br>"; // mod 2
?>
I have found some discussions including instructions CREATE and UNION, but I couldn't find other discussions around here that would help me with this division and distribution between tables to generate this new result.
You can solve this by next (a bit a complicate) query using window functions:
select
s.id, std student, tch teacher
from (
-- get Students with row_numbers
select
id,
row_number() over w as rn,
std
from tb_std
window w as (order by id)
) s
cross join (
-- get Teachers count and join to each student row
select count(*) tcnt from tb_tch
) tcnt
join (
-- select Teachers and join them to students depends row_number
-- divided to teachers count
select
row_number() over w as trn,
tch
from tb_tch
window w as (order by id)
) t on mod(s.rn, tcnt) = t.trn -1;
MySQL 8.0 fiddle
Result:
+====+=========+=========+
| id | student | teacher |
+====+=========+=========+
| 1 | S0 | T2 |
+----+---------+---------+
| 2 | S1 | T3 |
+----+---------+---------+
.........................
+----+---------+---------+
| 20 | S19 | T7 |
+----+---------+---------+
| 21 | S20 | T1 |
+----+---------+---------+
| 22 | S21 | T2 |
+----+---------+---------+
Related
I have tables like below.
Table A
id | val_a
1 | a1
2 | a2
3 | a3
Table B
id | id_a| val_b | resource_type
1 | 2 | b1 | 1
2 | 2 | b2 | 2
3 | 3 | b3 | 3
4 | 3 | b4 | 3
Table Resource_A
id |r_val| id_b
1 | ra1 | 1
Table Resource_B
id |r_val| id_b
1 | rb1 | 2
Table Resource_C
id |r_val| id_b
1 | rc1 | 3
2 | rc2 | 4
If resource_type is 1 in Table B, then table B make relation with table Resource_A.
If resource_type is 2 in Table B, then table B make relation with table Resource_B.
If resource_type is 3 in Table B, then table B make relation with table Resource_C.
Required Output is:
id_b | id_a| val_b |val_a | resource_type| r_val
1 | 2 | b1 | a1 | 1 | ra1
2 | 2 | b2 | a2 | 2 | rb1
3 | 3 | b3 | a3 | 3 | rc1
4 | 3 | b4 | a3 | 3 | rc2
But what is the best way to get it without using loop in laravel?
How Can I achieve this by using Laravel 5.2 OR Laravel 4 OR PHP OR MYSQL Query?
Thanks Ahead.
You only need to join the tables together as I have done below. The tricky part here is bringing in the correct r_val from the three resource tables. We can do this by left joining to each resource table, and then using the following expression to grab the matching value:
COALESCE(t1.r_val, t2.r_val, t3.r_val) AS r_val
This will take the first non NULL value from a resource table, in order of left to right. Assuming that each ID from tableb only appears once, in one of the resource tables, the order of the terms inside COALESCE() should not matter.
SELECT tb.id AS id_b,
tb.id_a,
tb.val_b,
COALESCE(ta.val_a, 'NA') AS val_a,
tb.resource_type,
COALESCE(t1.r_val, t2.r_val, t3.r_val) AS r_val
FROM tableb tb
LEFT JOIN tablea ta
ON tb.id_a = ta.id
LEFT JOIN resource_a t1
ON tb.id = t1.id_b
LEFT JOIN resource_b t2
ON tb.id = t2.id_b
LEFT JOIN resource_c t3
ON tb.id = t3.id_b
Demo here:
SQLFiddle
I have 2 database tables:
Table 1:
+---------+-------+-------------+
| Page | Title | Description |
+---------+-------+-------------+
| Apple | ..... | ........... |
| Orange | ..... | ........... |
| Pear | ..... | ........... |
| Grapes | ..... | ........... |
+---------+-------+-------------+
Table 2:
+----------+-------------+
| Link | Page |
+----------+-------------+
| Website1 | Apple |
| Website2 | Orange |
| Website3 | Apple |
| Website4 | Orange |
| Website5 | Apple |
| Website6 | Pear |
| Website7 | Apple |
| Website8 | Grapes |
| Website9 | Grapes |
+----------+-------------+
I want to know/return how many pages from Table 1 are referenced in Table 2 and how many times they are referenced. (I DON'T want to know how many times EACH page in Table 1 is referenced in Table 2).
So in this example:
1 page is referenced 1 time (Pear),
2 pages are referenced 2 times (Grapes and Orange) &
1 page is referenced 4 times.
What kind of SQL statement would I use to get this?
Following query should do..
SELECT COUNT(1) NoOfPages,CNT ReferencedTimes
FROM
(
SELECT T2.PAGE,COUNT(1) CNT
FROM TABLE1 T1 INNER JOIN TABLE2 T2 ON T1.PAGE = T2.PAGE
GROUP BY T2.PAGE
)T
GROUP BY CNT
I think the following statement will fit:
SELECT count(*) FROM Table2 WHERE (Table2.Page IN (SELECT Page FROM Table1));
Use This query
Select table2.page,cnt(table2.page)
from table1 inner join table2
On table1.Page=table2.Page group by table2.page
SELECT (GROUP_CONCAT(DISTINCT page)) AS Page,page_count
FROM
(SELECT table1.Page as page,COUNT(*) as page_count
FROM table1 INNER JOIN table2 ON table1.Page=table2.Page
GROUP BY table1.Page)
as T GROUP BY page_count
Hope this helps
If what you are seeking is X page was referenced N times, the below query will achieve that:
SELECT COUNT(t1.page), t2.count
FROM table1 t1
INNER JOIN (SELECT page,COUNT(*) AS count FROM table2 GROUP BY page) t2 ON t1.page=t2.page
GROUP BY t2.count
Try this query, it will make a left join and tell you how many times item is referenced in table2, if count is zero than no reference in the other table
SELECT table1.Page, count(table2.Page) as count
FROM table1
LEFT JOIN table2 ON table2.Page = table1.Page
GROUP BY table1.Page
I have a database with tables like below:
Reviews
id | review | companyid
companies
id | name
Now i want to get the data back so that i can show each company name with the total number of reviews for the company. Like seen below:
company 1 (company name) | 345
company 2 (company name) | 28
company 3 (company name) | 794
From here i will make a table using php to display the results
How can i achieve this with MYSQl?
Try this way:
SELECT Count(`r`.`review`) AS `total_reviews`,
`c`.`company`
FROM `reviews` AS `r`
JOIN `companies` AS `c`
ON `c`.`id` = `r`.`companyid`
Use COUNT and GROUP BY to count the reviews per company and use JOIN to get the company name from the other table.
Query
select t2.name as companyName,coalesce(t1.`count`,0) as `count` from
(
select companyid,count(companyid) as `count`
from reviews
group by companyid
)t1
right join companies t2
on t1.companyid= t2.id;
Sample Output
Table - reviews
+----+--------+-----------+
| id | review | companyid |
+----+--------+-----------+
| 1 | r1 | 1 |
| 2 | r2 | 2 |
| 3 | r3 | 1 |
+----+--------+-----------+
Table - companies
+----+------+
| id | name |
+----+------+
| 1 | C1 |
| 2 | C2 |
| 3 | C3 |
+----+------+
Output
+------+-------+
| name | count |
+------+-------+
| C1 | 2 |
| C2 | 1 |
| C3 | 0 |
+------+-------+
SQL Fiddle
You need to use a GROUP BY
SELECT r.companyid, c.name, count(r.id) as nb_review
FROM reviews r
INNER JOIN companies c ON (r.companyid = c.id)
GROUP BY r.companyid, c.name;
If you also want to see the companies with no reviews, do :
SELECT c.id, c.name, count(r.id) as nb_review
FROM companies c
LEFT JOIN reviews r ON (r.companyid = c.id)
GROUP BY c.id, c.name;
the question will require a bit long of an answer to explain due to my ignorance on SQL.
I hope it will not be viewed as vague because I have tried doing it by parts, but then I wont know which part exactly is causing which problem.(It really shows my level of knowledge on SQL.)
I have a code that was originally written in a PHP file, but I have decided I want to create a view table in order for the page to load faster.
The reason was because it does a loop to list the ranking of students and was taking too long for the web page to load.
Anyways, here is the code :
SELECT
SUM(VCA.meritPoint) AS merit,
VCA.student_no AS student_no,
P.program_code AS education_level,
P.name AS name,
P.gender AS gender,
P.campus_id AS campus_id
FROM viewcardactivity VCA
JOIN pupil P ON P.student_no = VCA.student_no
JOIN semester S ON S.id = '{$id}' -- MAX() AND (MAX() - 1)
AND DATE(VCA.tarikh) BETWEEN DATE(s.tarikhStart) AND DATE(s.tarikhEnd)
WHERE P.campus_id = '{$campus}' -- 1, 2
AND P.gender= '{$gender}' -- M, F
AND VCA.level= '{$level}' -- Diploma, Degree
AND P.program_code = (CONVERT(IF((SUBSTR(REPLACE(`p`.`program_code`,' ',''),3,1) = 1),'Diploma','Degree')USING latin1))
GROUP BY student_no ORDER BY merit DESC
As the name of the columns suggests, I would like to display more than one instead of specific ids, gender and level provided from the PHP variables.
The example output I would like to have is such as(based on the SQL Fiddle mock data :
table 'viewrankingmerit'
| merit | student_no | education_level | name | gender | campus_id |
---------------------------------------------------------------------
| 99 | 111111111 | Diploma | Ash | M | 1 |
---------------------------------------------------------------------
| 87 | 222222222 | Diploma |Belle | F | 1 |
---------------------------------------------------------------------
| 85 | 333333333 | Degree | Carl | M | 1 |
---------------------------------------------------------------------
| 80 | 444444444 | Degree | Deli | F | 1 |
---------------------------------------------------------------------
| 75 | 555555555 | Diploma | Eddy | M | 2 |
---------------------------------------------------------------------
| 74 | 666666666 | Diploma |Foxxy | F | 2 |
---------------------------------------------------------------------
| 50 | 777777777 | Degree | Greg | M | 2 |
---------------------------------------------------------------------
| 20 | 888888888 | Degree |Haley | F | 2 |
---------------------------------------------------------------------
As for the semester id, I would like to get the latest 2 ids. Which is the highest and second highest, based on the auto-generated id that will keep on increasing..
I was immediately stuck at trying to get 2 ids from table semester. I've tried using :
JOIN semester S1 ON S1.id = (SELECT MAX(s1.id) FROM semester)
AND DATE(VCA.tarikh) BETWEEN DATE(s1.tarikhStart) AND DATE(s1.tarikhEnd)
JOIN semester S2 ON S2.id = (SELECT MAX(s2.id)-1 FROM semester)
AND DATE(VKA.tarikh) BETWEEN DATE(s2.tarikhStart) AND DATE(s2.tarikhEnd)
It was probably a bad reference, but that was the closest solution I got so far.
1) Is it possible to do a table to show all the info?
2) If yes, how to get both S.id, P.campus_id, P.gender and VCA.level. Hoping that the solution would be alike.
3) If no, what is the best solution?
Thanks a lot guys.
[Edit] I've added a demo data in an SQL Fiddle
After some discussion in coments, this is the final result. I think.
select sum(vca.meritPoint) as merit,
vca.student_no AS student_no,
vca.type AS education_level,
p.name AS name,
p.gender AS gender,
p.campus_id AS campus_id
from
viewcardactiviti vca
inner join pupil p ON p.student_no = vca.student_no
inner join (select * from semester order by id desc limit 2) s
ON (vca.tarikh between s.tarikhStart and s.tarikhEnd
AND vca.type = s.level)
group by vca.student_no, vca.type, p.name, p.gender, p.campus_id
order by merit desc, p.campus_id;
See it here on SQLFiddle
If you need to filter for specific configurations like the parameters on your original query just add a WHERE clause.
This subquery (select * from semester order by id desc limit 2) will get the last to semesters based on the ID. And since there is no direct link (foreign key) between semester and viewcardactiviti you can use there join conditions ON (vca.tarikh between s.tarikhStart and s.tarikhEnd AND vca.type = s.level)
If you think that it still need to change anything let me know!
I have tables like this
mainTable
Id | name | country
1 | John | 5
2 | Bill | 7
categoriesTable
other_table_id | category
1 | 6
1 | 12
My question is how can I say
SELECT id FROM mainTable
WHERE country=5
AND WHERE categoriesTable order_table_id=[**THE ID I JUST GOT FROM THE FIRST TABLE**] && category=6 || category=12
Then returns the number of records that match so in this case 1
Thanks!
Doesn't anyone learn how to write JOINs when they learn SQL?
SELECT m.id
FROM mainTable AS m
JOIN categoriesTable AS c ON c.other_table_id = m.id
WHERE c.category IN (6, 12)
AND m.country = 5