I have a mySQL table with the following structure
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| make | varchar(55) | NO | MUL | NULL | |
| model | varchar(55) | NO | MUL | NULL | |
| year | varchar(4) | NO | MUL | NULL | |
+-------------+------------------+------+-----+---------+----------------+
and some sample data
('Chevrolet', 'Express', '2001'),
('Chevrolet', 'Express', '2002'),
('Chevrolet', 'Venture', '2001'),
('Chevrolet', 'Venture', '2002'),
('Dodge', 'Dakota', '2000'),
('Dodge', 'Dakota', '2001'),
('Ford', 'Flex', '2009'),
('Ford', 'Flex', '2010'),
What I want is one fast query that can return me all the models, with all the makes and years attached. So the following is an example of something I would like returned.
Array
(
[Chevrolet] => Array
(
[Express] => Array
(
[0] => 2001
[1] => 2002
)
[Venture] => Array
(
[0] => 2001
[1] => 2002
)
)
[Dodge] => Array
(
[Dakota] => Array
(
[0] => 2001
[1] => 2002
)
)
[Ford] => Array
(
[Flex] => Array
(
[0] => 2009
[1] => 2010
)
)
)
What I am currently doing:
I have one query to return all the unique makes:
$sql = "select distinct make from listings order by make asc ";
and once I have every make, I loop through and run the following query, using the make:
$sql = "select distinct model from listings where make = ? order by model asc ";
and I go one more step to grab the years:
$sql = "select distinct year from listings where make=? and model=? order by year desc";
SELECT make, model, year
FROM listings
ORDER BY make, model, year
Related
I have a query to find the count of rejected serialNos for different reasons. I need to find each reason count within a date limit.I have 3 tables say:
+------------------+--------------+------+-----+-------------------+
| Field | Type | Null | Key | Default |
+------------------+--------------+------+-----+-------------------+
| id | int(11) | NO | PRI | NULL |
| client_id | int(11) |YES | MUL | NULL |
| tc_date | datetime | YES | | NULL |
+------------------+--------------+------+-----+--------------------
mysql> desc job_order_finish_product_serial_no;
+------------------------------+--------------+------+-----+-----+
| Field | Type | Null | Key | Default|
+------------------------------+--------------+------+-----+-----|
id | int(11) | NO | PRI | NULL |
| serial_no | varchar(255) | YES | MUL | NULL |
| specification | json | YES | | NULL |
| client_id | int(11) |YES | MUL | NULL |
| tc_id | int(11) | YES | MUL | NULL |
| job_order_finish_products_id | int(11) | YES | MUL | NULL |
---------------------------------+-------------+-------+----+-------
In specification column my sample data looks like
"Leakage":{
"time":"2021-09-20 10:00:00",
"status":"completed",
"rework":[],
"user":{
"name":"xyz",
"id":1
}
},
"Thickness":{
"time":"2021-09-20 10:00:00",
"status":"rejected",
"rework":[],
"user":{
"name":"xyz",
"id":1
}
},
"Diameter":{
"time":null,
"status":"pending",
"rework":[],
"user":{
}
},
"Bung":{
"time":null,
"status":"pending",
"rework":[],
"user":{
}
}
}
For each serial_no in job_order_finish_product_serial_no, the specification should look like the above snippet. I need to get a count of each reason rejected serial_nos count within a date range. job_order_finish_product_serial_no row count was 2251543 rows.My count query is
select tc.tc_date,
(
SELECT count(serial_no)
from nucleus.job_order_finish_product_serial_no jfps
where jfps.tc_id=tc.id
and specification ->> "$.Thickness.status" = "rejected"
and client_id = 154
) as rejected_thickness,
(
SELECT count(serial_no)
from nucleus.job_order_finish_product_serial_no jfps
where jfps.tc_id=tc.id
and specification ->> "$.Leakage.status" = "rejected"
and client_id = 154
) as rejected_leakage,
(
SELECT count(serial_no)
from nucleus.job_order_finish_product_serial_no jfps
where jfps.tc_id=tc.id
and specification ->> "$.Bung.status" = "rejected"
and client_id = 154
) as rejected_bung
from nucleus.tc_details tc
inner join nucleus.job_order_finish_product_serial_no jfps
ON jfps.tc_id=tc.id
inner join nucleus.job_order_finish_products jofp
ON jofp.id=jfps.job_order_finish_products_id
where tc.tc_date between '2021-09-18 00:00:00'
AND '2021-09-22 23:59:59'
and tc.client_id=154
and jofp.client_id=154
and jfps.client_id=154
group by job_order_finish_product_id,tc.tc_date;
Output:
data rejected_thickness rejected_bung rejected_leakage rejected_diameter
21-09-2021 2 10 23 3
with the above query each subquery taking 2 min to give the result and the entire query taking almost taking 10min. Is there any way to optimize the query? Thank you!
Indexes that may help:
jfps, jofp: INDEX(tc_id, client_id) -- or in the opposite order
tc: INDEX(client_id, tc_date, id)
I prefer this way to write date range tests:
date >= '2021-09-18'
AND date < '2021-09-18' + INTERVAL 4 DAY
JOIN with a 'derived' table might be faster than 3 subqueries
unless count(serial_no) is needed for excluding NULL values of serial_no, use COUNT(*).
Something like
SELECT ...
SUM(jfps.specification ->> "$.Leakage.status" = "rejected")
as rejected_leakage,
SUM(...) as ...,
SUM(...) as ...,
...
JOIN nucleus.job_order_finish_product_serial_no AS jfps
ON jfps.tc_id = tc.id
WHERE ...
AND jfps.client_id = 154
I have tables for example called 'city':
+-----+---------------------+
| id | name |
+-----+---------------------+
| 2 | Amsterdam |
| 3 | The Hague |
| 8 | Barcelona |
| 10 | Rome |
| 11 | Paris |
| 12 | Rotterdam |
I need to select columns information in this format:
Array
(
[0] => Array
(
[Amsterdam] => 2
[The_Hague] => 3
...
)
)
I do not want to select the information like, and mapping that information to needed format:
Array
(
[0] => Array
(
[title] => Amsterdam
[value] => 2
)
[1] => Array
(
[title] => The_Hague
[value] => 3
)
)
Can I do it by using concat, json or something else?
it looks like you are using PHP. If so, you can do this:
/* fetch associative array */
while ($row = $result->fetch_assoc()) {
printf ("%s (%s)\n", $row["Name"], $row["CountryCode"]);
}
see https://www.php.net/manual/en/mysqli-result.fetch-assoc.php
I'm having trouble describing what I want so I'll try to illustrate it the best I can with arrays.
Array
(
[user1] => Array(
[title] => customtitle1
[prefix] => false
[worlds] => Array(
[119] => 367
[2] => 5
)
[time] => Array (
100
101
102
204
)
[last] => 119
)
[user2] => Array(
[title] => customtitle2
[prefix] => true
[worlds] => Array(
[119] => 367
[2] => 5
)
[time] => Array (
100
101
102
204
)
[last] => 119
)
)
I stored this in txt files but I moved on to SQL databases. How would I store this?
I only display 2 users here but it is more, the "worlds" array gets new values overtime (including new keys, so the length will change). Same goes for the "time" array, but only values.
username | title | prefix |
user1 | bla | true |
user2 | bl2 | false |
I don't know how I would go on implementing the worlds & time arrays. I would like to be able to sort these too.
Keep entities separate is one goal of good data modeling. Use one table to store one type of information, and another table to store another type, and relate them using foreign keys or join tables. Per your example, you might want a structure like this.
users:
| id | username | title | prefix | last_world |
| 1 | user1 | bla | true | 119 |
| 2 | user2 | bl2 | false | 119 |
worlds:
| user_id | worlds_id | other_id |
| 1 | 119 | 367 |
| 1 | 2 | 5 |
| 2 | 119 | 367 |
| 2 | 2 | 5 |
time:
| user_id | time |
| 1 | 100 |
| 1 | 101 |
| 1 | 102 |
| 1 | 204 |
| 2 | 100 |
| 2 | 101 |
| 2 | 102 |
| 2 | 204 |
These tables can be joined with a query like this:
SELECT
u.*,
w.worlds_id,
w.other_id,
t.time
FROM users u
INNER JOIN worlds w
ON u.id = w.user_id
INNER JOIN time t
ON u.id = t.user_id
Constructing your database schema so that data is never redundant (e.g. you update a username one and only one place) and data is never incorrect in one place but correct in another is called database normalization.
Good luck!
I'm getting some weird results when I query on of my tables to show upcoming birthdays (schema and query below), and then sort by date with the upcoming dates first. The type for the dob (date of birth) field is date with the format 0000-00-00
I'm using the below schema:
People:
+------------+-------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| fname | varchar(32) | NO | | NULL | |
| lname | varchar(32) | NO | | NULL | |
| dob | date | NO | | 0000-00-00 | |
| license_no | varchar(24) | NO | | NULL | |
| date_added | timestamp | NO | | CURRENT_TIMESTAMP | |
| status | varchar(8) | NO | | Allow | |
+------------+-------------+------+-----+-------------------+----------------+
and here's my query, as it's called from PHP:
<?php
/* This will give us upcoming dobs for the next 2 weeks */
$con = connect_db();
// grab any dobs coming up in the next week and sort them by what's
//coming up first
//if they are born on Feb. 29th, it will fall on March 1st
$query = 'select p.lname, p.fname, u.number, p.dob ' .
'from people p, units u where p.id = u.resident and ' .
'DAYOFYEAR(curdate()) <= DAYOFYEAR(DATE_ADD(dob, INTERVAL ' .
'(YEAR(NOW()) - YEAR(dob)) YEAR)) AND DAYOFYEAR(curdate()) +30 >= ' .
'dayofyear(`dob`) order by dayofyear(dob) limit 7;';
$result = mysqli_query($con, $query);
if (!empty($result)) {
while($row = mysqli_fetch_array($result)) {
$fname = $row['fname'];
$lname = $row['lname'];
$number = $row['number'];
$dob = date("m-d", strtotime($row['dob']));
if($dob == date("m-d")) {
$dob = 'Today!';
printf('%s, %s</br>Unit: %s</br>%s</br></br>', $lname,
$fname, $number, $dob);
} else {
printf('%s, %s</br>Unit: %s</br>Date: %s</br></br>', $lname,
$fname, $number, $dob);
}
}
}
?>
here's an example of the returned query:
Name, Name
Unit: 110
Date: 09-11
Name2, Name2
Unit: 434
Date: 09-10
As you can see, the order is wrong!
EDIT - Now I've noticed that the records in question (the two dates above) are not ordered correctly ever in MySQL!
One of the full dates is: 1950-09-11
and the other is: 1956-09-10
I've looked through those two records and haven't found any mangled data, so I'm pretty confused as to why this is happening
ORDER BY dayofyear(dob) ASC
Good luck
I have a table that looks like:
+--------------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+-------------+------+-----+---------+-------+
| ProductsDownloadId | int(11) | NO | PRI | 0 | |
| RCContactID | int(11) | NO | MUL | NULL | |
| product_name | varchar(50) | YES | MUL | NULL | |
| download_date | timestamp | YES | | NULL | |
+--------------------+-------------+------+-----+---------+-------+
I'm writing a module for this table to be viewable in a Drupal 6 View.
I followed the example I found here:
http://drupalcontrib.org/api/drupal/contributions--views--docs--docs.php/function/hook_views_data/6
So I exposed the download_date as thus:
$data['products_downloaded']['download_date']=array(
'title'=>t("Download Date"),
'help'=>t("When Product was downloaded by the user"),
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'filter' => array(
'handler' => 'views_handler_filter_date',
),
);
But when I add it to a view, all the dates are displayed as "12/31/1969 - 19:33". And none of the dates in my table are:
EDIT: Corrected query:
mysql> select count(1) from products_downloaded where download_date <'2000-12-31 23:59:59.999999';
+----------+
| count(1) |
+----------+
| 0 |
+----------+
1 row in set (0.04 sec)
I also did a custom date format with the format 'r' in the View and I got
Wed, 31 Dec 1969 19:33:31 -0500 for all the dates.
So what did I do wrong on my module?
Your query:
select count(1) from products_downloaded where download_date <'12/31/2000 - 19:33'
Your problem here is that MySQL expects dates to be given in a different format to that.
You need to provide your dates in the following format:
'2007-12-31 23:59:59.999999'
(you can drop the microseconds, seconds, etc to get the precision you need as required)
So in your case, your query should look like this:
select count(1) from products_downloaded where download_date <'2000-12-31 19:33'
This should query the field correctly.
By the way -- If you have dates showing up unexpectedly as 1969, it implies that perhaps you've been using the wrong format in other queries as well. You may want to check that too.
See the MySQL manual page for date times: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html
What I was able to determine was that PHP or Drupal wasn't able to understand whatever was being returned to the processor. I messed around with a custom hook and got the value to be accepted by the DateTime constructor. From there . . . it was easy to get the date formats back.