create a morris chart in Laravel - php

so I was able to build a Morris chart following some tutorials, and this is what I've come up with so far
$range = \Carbon\Carbon::now()->subDays(30);
$stats = DB::table('tickets')
->where('created_at', '>=', $range)
->groupBy('date')
->orderBy('date', 'ASC')
->get([
DB::raw('Date(created_at) as date'),
DB::raw('COUNT(*) as value')
])
->toJSON();
OUTPUT
"[{"date":"2018-11-10","value":1},{"date":"2018-11-11","value":1}]"
the thing is I'm trying to get the results by months and ticket status not daily.
js code
Morris.Area({
element: 'morris-area-chart'
, data: data
, xkey: 'date'
, ykeys: ['status']
});
Tickets Table
id|phone_model |cus_name |issue |notes |created_at |updated_at |status
Expected Output
[{"date":"11","tickets":2,"status":1},{"date":"11","tickets":1,"status":2},
{"date":"10","tickets":3,"status":1},{"date":"10","tickets":1,"status":3},]
I tried more than a way to get the results based on months and ticket status but no luck
any help will be appreciated, Thank you.

You can use this query:
$result_arr = \DB::select("SELECT DATE_FORMAT(created_at, '%m') date, status, COUNT(*) count FROM tickets GROUP BY date, status ORDER BY date DESC");
return collect($result_arr)->toJson();
It outputs such a result for example(Output is in mysql console here):
+------+--------+-------+
| date | status | count |
+------+--------+-------+
| 12 | 1 | 1 |
| 12 | 2 | 3 |
| 12 | 4 | 1 |
| 12 | 10 | 7 |
| 11 | 1 | 1 |
| 11 | 2 | 1 |
| 11 | 4 | 1 |
| 10 | 1 | 3 |
| 10 | 2 | 2 |
| 10 | 3 | 1 |
| 10 | 4 | 2 |
| 09 | 1 | 2 |
| 09 | 2 | 7 |
| 09 | 3 | 5 |
| 08 | 1 | 1 |
| 08 | 2 | 1 |
| 08 | 12 | 1 |
| 07 | 1 | 4 |
| 06 | 1 | 1 |
| 06 | 2 | 12 |
| 06 | 3 | 2 |
| 05 | 1 | 1 |
| 05 | 2 | 8 |
| 05 | 11 | 1 |
| 04 | 1 | 2 |
| 04 | 2 | 8 |
| 04 | 10 | 1 |
| 03 | 1 | 2 |
| 02 | 1 | 2 |
| 02 | 2 | 26 |
| 02 | 3 | 1 |
| 02 | 11 | 2 |
| 02 | 12 | 1 |
| 01 | 2 | 21 |
| 01 | 3 | 8 |
| 01 | 10 | 6 |
+------+--------+-------+
36 rows in set (0.00 sec)
Keep in mind that as you want to group the results based on both status & date it does not give you just a row for each date(as you may have multiple statuses), so for each date you may have different values for each status.
See Mysql Docs for more about DATE_FORMAT.

Related

How to filter users' data sets by narrowing it from the same data sets in SQL? - 61 joins limit problem

I'm implementing sport testing system where people enter their exercises results.
I'm trying to list the results of exercises filtered with values of other exercises' results.
I use a Codeigniter framework to building SQLs.
Here are the db tables:
"tests"
| id | users_id | test_date |
------------------------------
| 1 | 1 | 2020-03-10 |
| 2 | 1 | 2020-03-12 |
| 3 | 2 | 2020-03-09 |
| 4 | 2 | 2020-03-13 |
"exercises"
| id | name |
------------------
| 1 | exercise1 |
| 2 | exercise2 |
| 3 | exercise3 |
| 4 | exercise4 |
| 5 | exercise5 |
| 6 | exercise6 |
"results"
| id | tests_id | exercieses_id | result |
------------------------------------------
| 1 | 1 | 1 | 35 |
| 2 | 1 | 2 | 12 |
| 3 | 1 | 3 | 23 |
| 4 | 1 | 4 | 34 |
| 5 | 1 | 5 | 45 |
| 6 | 1 | 6 | 56 |
| 7 | 2 | 1 | 67 |
| 8 | 2 | 2 | 12 |
| 9 | 2 | 3 | 54 |
| 10 | 2 | 4 | 89 |
| 11 | 2 | 5 | 35 |
| 12 | 2 | 6 | 31 |
| 13 | 3 | 1 | 35 |
| 14 | 3 | 2 | 12 |
| 15 | 3 | 3 | 23 |
| 16 | 3 | 4 | 34 |
| 17 | 3 | 5 | 45 |
| 18 | 3 | 6 | 56 |
| 19 | 4 | 1 | 67 |
| 20 | 4 | 2 | 12 |
| 21 | 4 | 3 | 54 |
| 22 | 4 | 4 | 89 |
| 23 | 4 | 5 | 35 |
| 24 | 4 | 6 | 31 |
The base query is:
$this->db->select('exercises.id, exercises.name, results.result, tests.test_date');
$this->db->from('results');
$this->db->join('tests', 'tests.id = results.tests_id');
$this->db->join('exercises', 'exercises.id = results.exercises_id');
$this->db->order_by('exercises.id');
and it works well.
Now I'm adding a filtering of all results with the selected narrowing ranges of results defined by min and max values. They are packed in array:
$exercises_results_to_filter = array('exercise1' => array('id' => 1, 'min' => 20, 'max' => 30),
'exercise2' => array('id' => 2, 'min' => 24, 'max' => 28),
... and so on);
Because I have a lot of exercises so I make this loop:
foreach ($exercises_results_to_filter as $name => $exercise)
{
$this->db->join('results AS results_'.$name, 'results_'.$name.'.tests_id = results.tests_id', 'INNER');
$this->db->where('results_'.$name.'.exercises_id = '.$exercise['id']);
$this->db->where('results_'.$name.'.result BETWEEN '.$exercise['min'].' AND '.$exercise['max']);
}
and above query also works well, but only for small amount of JOINs. When 200 exercises go into the work mySQL shouts at me that "Too many tables; MySQL can only use 61 tables in a join"
Please help. What to do??

How to display the frequency count in several mysql tables in codeigniter

How can I display the frequency of the number of students in a class. I have several tables in the database.
table = kelas
+----+---------+---------+
| id | tingkat | nama |
+----+---------+---------+
| 1 | 5 | Kelas 5 |
| 2 | 3 | Kelas 3 |
+----+---------+---------+
table = siswa
+----+----------+
| id | nama |
+----+----------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
etc.
table = kelas_siswa
+----+----------+----------+------+
| id | id_kelas | id_siswa | ta |
+----+----------+----------+------+
| 18 | 1 | 18 | 2019 |
| 19 | 1 | 19 | 2019 |
| 20 | 1 | 20 | 2019 |
| 21 | 1 | 21 | 2019 |
| 22 | 1 | 22 | 2019 |
| 23 | 1 | 23 | 2019 |
| 24 | 1 | 24 | 2019 |
| 25 | 1 | 25 | 2019 |
| 26 | 1 | 26 | 2019 |
| 27 | 1 | 27 | 2019 |
| 28 | 1 | 28 | 2019 |
| 29 | 1 | 29 | 2019 |
| 30 | 1 | 30 | 2019 |
| 31 | 1 | 31 | 2019 |
| 1 | 2 | 1 | 2019 |
| 2 | 2 | 2 | 2019 |
| 3 | 2 | 3 | 2019 |
| 4 | 2 | 4 | 2019 |
| 5 | 2 | 5 | 2019 |
| 6 | 2 | 6 | 2019 |
| 7 | 2 | 7 | 2019 |
| 8 | 2 | 8 | 2019 |
| 9 | 2 | 9 | 2019 |
| 10 | 2 | 10 | 2019 |
| 11 | 2 | 11 | 2019 |
| 12 | 2 | 12 | 2019 |
| 13 | 2 | 13 | 2019 |
| 14 | 2 | 14 | 2019 |
| 15 | 2 | 15 | 2019 |
| 16 | 2 | 16 | 2019 |
| 17 | 2 | 17 | 2019 |
+----+----------+----------+------+
How do I display data on the number of students for kelas 3 and kelas 5. on :
.$JUMLAH_SISWA.
For example Class 3 there are 17 students and Class 5 there are 14 Students
public function index() {
$d=array();
$ambil_data_kelas = $this->db->query("SELECT id, nama FROM m_kelas ORDER BY tingkat ASC, nama ASC")->result_array();
$tampil = "";
if (!empty($ambil_data_kelas)) {
foreach ($ambil_data_kelas as $v) {
$tampil .= '<div class="col-md-4"><div class="panel panel-info">
<div class="panel-heading"><b>'.$v['nama'].' jumlah siswa : '.$JUMLAH_SISWA.'</b></div>
<div class="panel-body" style="height: 300px; overflow: auto">
<table class="table table-stripped">
<thead>
<tr><th>No</th><th>Nama</th><th>Aksi</th></tr>
</thead>
<tbody>';
$q_siswa_per_kelas = $this->db->query("SELECT
a.id, b.nama nmsiswa, a.id_kelas
FROM t_kelas_siswa a
INNER JOIN m_siswa b ON a.id_siswa = b.id
WHERE a.id_kelas = '".$v['id']."'
AND a.ta = '".$this->d['ta']."'
ORDER BY b.nis ASC, b.nama ASC")->result_array();
if (!empty($q_siswa_per_kelas)) {
$no = 1;
foreach ($q_siswa_per_kelas as $k) {
$tampil .= '<tr><td>'.$no++.'</td><td>'.$k['nmsiswa'].'</td><td class="ctr"><i class="fa fa-remove"></i></td></tr>';
}
}
$tampil .= '</tbody></table></div></div></div>';
}
}
$this->d['tampil'] = $tampil;
$this->d['p'] = "list";
$this->load->view("template_utama", $this->d);
}
To count the number of students in each class you only need:
SELECT id_kelas, COUNT(*) 'count'
FROM kelas_siswa
GROUP BY id_kelas
and then you can bolt on additional JOINs to include whatever else you need like class metadata.
Eg:
SELECT ks.id_kelas, k.name, COUNT(*) 'count'
FROM kelas_siswa ks INNER JOIN kelas k
ON ks.id_kelas = k.id
GROUP BY ks.id_kelas
Or getting fancy:
SELECT ks.id_kelas, k.name, COUNT(*) 'count', GROUP_CONCAT(s.nama) 'students'
FROM kelas_siswa ks INNER JOIN kelas k
ON ks.id_kelas = k.id
INNER JOIN siswa s
ON ks.id_siswa = s.id
GROUP BY ks.id_kelas
Which will also list all the student names along with the count.

generate sequential reference numbers

I am generating sequential reference numbers like complaint/1, complaint/2 when an insertion is made. I get what the previously generated value is (complaint/2) and then increment.
But when two users submit at the same time, I sometimes get same reference nos for both complaints.
How do I prevent this?
SELECT RIGHT(Date_format(from_financial_year_,'%Y'),2),
RIGHT(Date_format(to_financial_year_,'%Y'),2)
INTO from_financial_year_,
to_financial_year_;SELECT rec.receipt_ref_no
INTO last_receipt_ref_num_
FROM svk_apt_receipts rec
WHERE Replace(Substring_index(rec.receipt_ref_no, '/', 2),'REC/','') = Concat(from_financial_year_,to_financial_year_)
AND rec.customer_id = customer_id_
AND rec.association_id = association_id_
ORDER BY rec.receipt_id DESC limit 1;IF(last_receipt_ref_num_ IS NULL) then
SELECT 1
INTO max_ref_id_;
else
SELECT (replace(last_receipt_ref_num_, concat('REC/',from_financial_year_,to_financial_year_,'/'),'')+1)
INTO max_ref_id_;ENDIF;SELECT Concat('REC/',from_financial_year_,to_financial_year_,'/',max_ref_id_)
INTO receipt_ref_no_;INSERT INTO svk_apt_receipts
(
receipt_ref_no, paid, payable, is_paid, master_receipt_to_id, receipt_from_id, receipt_to_id, receipt_date,
receipt_mode, transaction_ref_no, customer_id, association_id, is_active, created_by, created_on, receipt_status_id, remarks
)
VALUES
( receipt_ref_no_, _total_amount, 0,1,3, receipt_from_id_, receipt_to_id_, Cast(Now()AS DATE), 3, _transaction_ref_no,
customer_id_, association_id_, 1, _created_by, Now(), 2, 'Paid through Payment Gateway'
);
As mentioned in comments, just store an autoincrementing id. All the other stuff can be handled by trivial queries and/or your presentation layer.
By way of example...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id SERIAL PRIMARY KEY
,user INT NOT NULL
);
INSERT INTO my_table (user) VALUES
(1),(1),(3),(3),(5),(2),(1),(8),(4),(5),(7),(5),(5),(4),(1),(2),(3),(6),(4),(6),(1),(5),(1),(8);
SELECT * FROM my_table;
+----+------+
| id | user |
+----+------+
| 1 | 1 |
| 2 | 1 |
| 3 | 3 |
| 4 | 3 |
| 5 | 5 |
| 6 | 2 |
| 7 | 1 |
| 8 | 8 |
| 9 | 4 |
| 10 | 5 |
| 11 | 7 |
| 12 | 5 |
| 13 | 5 |
| 14 | 4 |
| 15 | 1 |
| 16 | 2 |
| 17 | 3 |
| 18 | 6 |
| 19 | 4 |
| 20 | 6 |
| 21 | 1 |
| 22 | 5 |
| 23 | 1 |
| 24 | 8 |
+----+------+
24 rows in set (0.01 sec)
SELECT x.*
, COUNT(*) complaint
FROM my_table x
JOIN my_table y
ON y.user = x.user
AND y.id <= x.id
GROUP
BY x.id
ORDER
BY user
, id;
+----+------+-----------+
| id | user | complaint |
+----+------+-----------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 7 | 1 | 3 |
| 15 | 1 | 4 |
| 21 | 1 | 5 |
| 23 | 1 | 6 |
| 6 | 2 | 1 |
| 16 | 2 | 2 |
| 3 | 3 | 1 |
| 4 | 3 | 2 |
| 17 | 3 | 3 |
| 9 | 4 | 1 |
| 14 | 4 | 2 |
| 19 | 4 | 3 |
| 5 | 5 | 1 |
| 10 | 5 | 2 |
| 12 | 5 | 3 |
| 13 | 5 | 4 |
| 22 | 5 | 5 |
| 18 | 6 | 1 |
| 20 | 6 | 2 |
| 11 | 7 | 1 |
| 8 | 8 | 1 |
| 24 | 8 | 2 |
+----+------+-----------+
24 rows in set (0.00 sec)

SQL request for several tables and operations in MySQL

I have the following 3 tables: unit, stage, stats.
unit stage
+----+--------+ +----+-------+---------------------+
| id | status | | id |unit_id| date |
+----+--------+ +----+-------+---------------------+
| 1 | 2 | | 1 | 2 | 2013-11-22 00:00:00 |
| 2 | 3 | | 2 | 2 | 2013-11-26 12:00:00 |
| 3 | 3 | | 3 | 3 | 2013-10-11 00:00:00 |
| 4 | 0 | | 4 | 1 | 2013-12-29 00:00:00 |
+----+--------+ +----+-------+---------------------+
stats
+----+----------+---------------------+-------+
| id | stage_id | date | clicks|
+----+----------+---------------------+-------+
| 1 | 1 | 2013-11-22 00:00:00 | 10 |
| 2 | 1 | 2013-11-23 00:00:00 | 20 |
| 3 | 1 | 2013-11-24 00:00:00 | 25 |
| 4 | 2 | 2013-11-26 00:00:00 | 15 |
| 5 | 2 | 2013-11-27 12:00:00 | 21 |
| 6 | 3 | 2013-12-29 00:00:00 | 8 |
+----+----------+---------------------+-------+
I need a request, that will produce the following response:
+---------+---------------------+-----------------------+
| unit.id | stage.min.date | sum(stats.max.clicks) |
+---------+---------------------+-----------------------+
| 2 | 2013-11-22 00:00:00 | 46 |
| 3 | 2013-12-29 00:00:00 | 8 |
+---------+---------------------+-----------------------+
by the following rules:
1) unit.id - show only units with unit.status=3
2) stage.min.date - minimal stage.date for corresponding unit_id
3) sum(stats.max.clicks) - sum of stats.clicks with max dvalues for each stage_id associated with corresponding unit_id. In my example 46 = 25(stage_id=1) + 21(stage_id=2)
The problem is in min.date and sum of clicks - I have no idea how to get it in one query. Definitely it`s not a problem to do it using php code and several requests.
Schema in SQL Fiddle
Thanks in advance.
I just ask myself, why I do this? Your example resonse has an error, and does not match your fiddle... but:
SELECT
cc.unit_id, MIN(cc.date) as stage_min_date , SUM(dd.clicks) as stats_max_clicks
FROM
stage cc
LEFT JOIN (
SELECT
bb.stage_id, bb.clicks
FROM
stats bb LEFT JOIN (
SELECT id, stage_id, MAX(date) AS max_date
FROM stats
GROUP BY stage_id
) aa
ON
aa.max_date = bb.date
WHERE
aa.max_date IS NOT NULL
) dd
ON cc.id = dd.stage_id
LEFT JOIN unit ee
ON ee.id = cc.unit_id
WHERE ee.status = 3
GROUP BY cc.unit_id
...

Selecting rows with max value in range

I have the followng data:
+----+---------+---------------------+-------+
| id | site_id | datetime | views |
+----+---------+---------------------+-------+
| 1 | 1 | 2013-11-01 23:59:59 | 12 |
| 2 | 1 | 2013-11-02 23:59:59 | 15 |
| 3 | 1 | 2013-11-03 23:59:59 | 18 |
| 4 | 1 | 2013-11-04 23:59:59 | 29 |
| 5 | 1 | 2013-11-05 23:59:59 | 38 |
| 6 | 1 | 2013-11-05 12:59:59 | 40 |
| 7 | 1 | 2013-11-06 23:59:59 | 45 |
| 8 | 1 | 2013-11-07 23:59:59 | 49 |
| 9 | 1 | 2013-11-08 23:59:59 | 52 |
| 10 | 2 | 2013-11-04 23:59:59 | 25 |
| 11 | 2 | 2013-11-05 21:59:59 | 42 |
| 12 | 2 | 2013-11-06 23:59:59 | 60 |
| 13 | 2 | 2013-11-07 23:59:59 | 75 |
| 14 | 2 | 2013-11-08 23:59:59 | 86 |
| 15 | 2 | 2013-11-09 23:59:59 | 90 |
| 16 | 2 | 2013-11-10 23:59:59 | 92 |
| 17 | 2 | 2013-11-11 23:42:59 | 98 |
+----+---------+---------------------+-------+
I would pass a day and wish to get the rows with the highest time in the given day or if there`s no records for this site for this day, the last available row in the past.
e.g. for 2013-11-01
+----+---------+---------------------+-------+
| id | site_id | datetime | views |
+----+---------+---------------------+-------+
| 1 | 1 | 2013-11-01 23:59:59 | 12 |
+----+---------+---------------------+-------+
for 2013-11-05
+----+---------+---------------------+-------+
| id | site_id | datetime | views |
+----+---------+---------------------+-------+
| 5 | 1 | 2013-11-05 23:59:59 | 38 |
| 11 | 2 | 2013-11-05 21:59:59 | 42 |
+----+---------+---------------------+-------+
and for 2013-11-10
+----+---------+---------------------+-------+
| id | site_id | datetime | views |
+----+---------+---------------------+-------+
| 9 | 1 | 2013-11-08 23:59:59 | 52 |
| 16 | 2 | 2013-11-10 23:59:59 | 92 |
+----+---------+---------------------+-------+
Thanks in advance.
You can try this:
SELECT a.id,a.site_id,b.maxDate,a.views
FROM table1 a
INNER JOIN (
SELECT site_id ,MAX(datetime) as maxDate
FROM table1
WHERE datetime < DATEYOUWANTTOSEE + INTERVAL 1 DAY
GROUP BY site_id
) b ON a.site_id = b.site_id AND a.datetime = b.maxDate
The inner query will get you the MAX(datetime) for each site_id. Then you join it with your table to get the rest of the information.
sqlfiddle demo
SELECT * FROM <tablename> WHERE datetime = <datetime> ORDER BY datetime DESC LIMIT 2
You data and examples do not really match themselves, nor the description, but what you probably are looking for is this:
Select top 1 *
from table
where date(datetime) <= date(#PARAMETER)
order by datetime desc
I believe this should work:
SELECT SUBSTRING(`datetime`, 1, 10) AS date, MAX(`views`)
FROM table
GROUP BY SUBSTRING(`datetime`, 1, 10)
If you need the id/site_id as well, write it in your post, as it is not clear
SQLFiddle to show you the result:
http://sqlfiddle.com/#!2/e0ccb3/1

Categories