I have the following PHP script, which executes a MySQL-Query.
$sSql = "SELECT DISTINCT t1.* "
. "FROM import_data t1 "
. "INNER JOIN import_profiles imp on t1.profile_id = imp.id "
. "WHERE imp.creditornr = " . $vendor . " "
. "AND t1.vendor = '" . $k . "' "
. "AND t1.importRun = (SELECT MAX(importRun) AS importRun
FROM import_data
WHERE sku=t1.sku
AND profile_id = t1.profile_id)";
In native SQL, a query looks like this:
SELECT DISTINCT t1.*
FROM import_data t1
INNER JOIN import_profiles imp on t1.profile_id = imp.id
WHERE imp.creditornr = 73329
AND t1.vendor = 'rackmountit'
AND t1.importRun = (SELECT MAX(importRun) AS importRun
FROM import_data
WHERE sku=t1.sku
AND profile_id = t1.profile_id)
This is the explain of one of those queries: (I run > 10 of those) and the DB currently has ~100.000 entries (rising).
Also, those are the tables which are used in this statements:
import_data
import_profiles
I have no idea how, since I'm not that good in mysql, but are there any ideas how to increase the performance of those (sub)queries? Currently they are running > 1:00 and I need to optimize it.
Thanks and let me know, if you need further information.
EDIT 1
Added the CREATE TABLE statements
SET NAMES utf8;
SET time_zone = '+00:00';
CREATE TABLE `import_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`profile_id` int(11) NOT NULL,
`sku` varchar(255) NOT NULL,
`vendor` varchar(255) NOT NULL,
`evp` double NOT NULL,
`ek` double NOT NULL,
`articletext1` text NOT NULL,
`articletext2` text NOT NULL,
`ean` text NOT NULL,
`stock` int(11) NOT NULL,
`zolltarif` int(11) NOT NULL,
`tstamp` date NOT NULL,
`importRun` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `import_profiles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`creditornr` int(6) NOT NULL,
`structure` text NOT NULL,
`updatetime` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Import-Profile für Vorlieferanten';
You should add indexes for fields: import_data.profile_id, import_data.sku and import_profiles.creditornr it should increase your SQL queries speed
This will depend on your schema and how your data actually looks like.
The vendor field seems like a good candidate for putting an index on it. But that depends on how unique it is. If every row of the vendor column is unique, then look for something else to filter on.
Using an analogy of shopping for groceries:
As I mentioned in the column, going to temporary is like having a very long grocery list, copying all or almost all of the entire list to a new sheet of paper, and THEN going through the copy to find which items in the list are appropriate to the grocery isle you are in.
Edit: SO answer for how to add indexes, recommend reading comments as well. - https://stackoverflow.com/a/3002635/9908
import_data: INDEX(sku, profile_id, importRun) -- for the MAX subquery
import_data: INDEX(vendor)
import_profiles: INDEX(creditornr, id)
(It is unclear which of the last two to have, but it won't hurt to include both.)
Since your query is somewhat a "groupwise max", see groupwise max.
Related
I use grocery-crud for a simple SQL select
$crud->set_table('lista_ab');
$crud->set_relation('id_ab','lista_ab_term','Expire');
The problem is that it does not make the relation for 'id_ab'
My database looks
CREATE TABLE `lista_ab` (
`id_ab` int(10) NOT NULL,
`Subname` varchar(255) DEFAULT NULL,
`Name` varchar(255) DEFAULT NULL,
`Inregistrat` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `lista_ab_term` (
`ID` int(10) NOT NULL,
`id_ab` int(10) DEFAULT NULL,
`Expire` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
In final I want to extract Subname and Expire.
You cannot create dropdown list and show field name of the first table : Subname, but you can have as many fields you like to call from the other table and the syntax is really simple.
Just at the 3rd field you will have the symbol { and } . So it will be for example:
$crud->set_relation('id_ab','lista_ab_term','{Expire} - {ID}');
You can use join query like this for your expected results:
SELECT t1.Subname, t2.Expire FROM lista_ab t1 LEFT JOIN lista_ab_term t2 ON t1.id_ab = t2.id_ab
Or In Codeigniter
$this->db->select('lista_ab.Subname,
lista_ab_term.Expire');
$this->db->from('lista_ab');
$this->db->join('lista_ab_term', 'lista_ab.id_ab= lista_ab_term.id_ab');
$q = $this->db->get();
Okay so now its display results like 3 times in a row
$user_apps = mysql_query("SELECT a.name,a.download_url FROM user_apps as ua LEFT JOIN
apps as a ON (ua.app_id=a.app_id)
WHERE ua.user_id='$user_id'") or die(mysql_error());
while($raw = mysql_fetch_array($user_apps)){
$name = $raw['name'];
$url = $raw['download_url'];
echo $name;
echo "<br />";
echo $url;
}
Database Table Structure(since I am new to the site and did not know how to display the table structure I just exported the sql)
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
CREATE TABLE IF NOT EXISTS `user_apps` (
`user_id` int(11) NOT NULL,
`app_id` int(11) NOT NULL,
KEY `user_id` (`user_id`,`app_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `apps` (
`app_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`description` text NOT NULL,
`icon` varchar(255) NOT NULL,
`download_url` varchar(255) NOT NULL,
`default` int(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`app_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;
I'v tried different Join types but that does not seem to work.
Used the join query for get the result check bellow example query
$user_apps = mysql_query("SELECT DISTINCT a.name,a.download_url FROM user_apps as ua LEFT JOIN apps as a ON (ua.app_id=a.app_id) WHERE ua.user_id='$user_id'") or die(mysql_error());
while($raw = mysql_fetch_array($user_apps)){
$name = $raw['name'];
$url = $raw['download_url'];
echo $name;
echo $url;
}
change the join type as per your requirement. the above query for only example
INNER JOIN: Returns all rows when there is at least one match in BOTH
tables
LEFT JOIN: Return all rows from the left table, and the matched rows
from the right table
RIGHT JOIN: Return all rows from the right table, and the matched
rows from the left table
FULL JOIN: Return all rows when there is a match in ONE of the tables
more about join click here
AND also check this http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
You have used single quotes in query at user_id='$user_id' .
Are you sure your user_id is char, varchar or text? Just print_r($user_apps) and check it has any records or not? If user_id is int,tinyin than remove single quote.
I have two tables one containing a selection of values in different categories and the other ‘master’ table referencing the text values by the first primary key.
Table 1
CREATE TABLE IF NOT EXISTS `defaultvalues` (
`default_ID` int(11) NOT NULL AUTO_INCREMENT,
`columnName` varchar(100) NOT NULL,
`defaultValue` varchar(100) NOT NULL,
PRIMARY KEY (`default_ID`),
UNIQUE KEY `columnName` (`columnName`,`defaultValue`)
)
Table 2
CREATE TABLE IF NOT EXISTS `master` (
`master_ID` int(11) NOT NULL AUTO_INCREMENT,
`size` int(11) NOT NULL,
`madeby` int(11) NOT NULL,
`type` int(11) NOT NULL,
`colour` int(11) NOT NULL,
`notes` text NOT NULL,
`issueDate` datetime NOT NULL,
`ceMark` text NOT NULL,
`batchNumber` text NOT NULL,
PRIMARY KEY (master_ID)
)
The master.size for each row is a P.key in the defaultvalues table.
E.g. master.colour = 234, 234=defaultvalues.defaultValue = ‘red’
E.g. master.size = 345, 345=defaultvalues.defaultValue = ‘small’
Now I would like to run a query that returns the ‘master’ table with text values in columns colour, size, type, madeby from ‘defaultvalues. defaultValue’ and ready for further processing.
I have been trying with sub queries and temp tables but I can’t get it to work
The current system relies on PHP and multiple queries and building arrays.
There has to be a more elegant solution.
I hope this makes sense.
Any hints or advice much appreciated.
Dave
You'll need to join the master table to the defaultvalues table multiple times. Something like this:
SELECT m.*, d.defaultvalue as sizevalue, d2.defaultvalue as colorvalue...
FROM master m
JOIN defaultvalues d ON m.size = d.default_id
JOIN defaultvalues d2 ON m.color = d2.default_id
...
What i did in the end.... while it works I am still not happy. There must be something better...
SELECT m.*,
(SELECT defaultValue FROM defaultvalues WHERE default_ID = m.colour) AS myColour ,
(SELECT defaultValue FROM defaultvalues WHERE default_ID = m.size) AS mySize
FROM master m
WHERE m.master_ID = 1;
I can use LIMIT to surrender myself to one row but I would like to learn how I can provide one of each rows rather than the several of the same rows / data
Goto : http://inks-etc.com/Script/SQL/loginform.php
Username: jason
Password: 123
Sounds like you have this setup:
create table `some_table` (
`uniq_id` bigint(20) unsigned not null auto_incremenet,
`some_data` varchar(200) not null,
`some_other_data` varchar(100) not null,
PRIMARY KEY (`uniq_id`)
) ENGINE=MyISAM AUTO_INCREMENT=260285 DEFAULT CHARSET=utf8;
create table `some_other_table` (
`other_id` bigint(20) unsigned not null auto_incremenet,
`link_to_uniq_id` bigint(20) unsigned not null,
`multiple_entry_data` varchar(100) not null,
PRIMARY KEY (`uniq_id`)
) ENGINE=MyISAM AUTO_INCREMENT=260285 DEFAULT CHARSET=utf8;
Where some_other_table can match some_table multiple times. It also sounds like you are trying something like this, and wanting one row per uniq_id:
select * from some_table
inner join some_other_table
on some_table.uniq_id = some_other_table.link_to_uniq_id
The way that you can modify this type of query to get only one entry per uniq_id is something like this, using the group by directive:
select * from some_table
inner join some_other_table
on some_table.uniq_id = some_other_table.link_to_uniq_id
group by some_table.uniq_id
Hopefully I understood your question, and hopefully this answers it.
I am a bit new to sql and php so I need some help here. I created two tables and I want to establish a 'one-to-many relationship' but I can't figure out how I can give the data through the php file. Here is some code:
CREATE TABLE `details` (
`details_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL,
`latitude` double NOT NULL,
`longitude` double NOT NULL,
`mytext` varchar(60) NOT NULL,
`description` varchar(600) NOT NULL,
`city_details` int(11) NOT NULL,
PRIMARY KEY (`details_id`),
FOREIGN KEY (`city_details`) REFERENCES city(`city_id`)
on update cascade
);
CREATE TABLE `city` (
`city_id` int(11) NOT NULL AUTO_INCREMENT,
`cityName` varchar(30) NOT NULL,
PRIMARY KEY (`city_id`)
);
So I want to write a cityName and then be able to give some data for various places of the city. How can I create a php file so that I will only have to give the name of the city (to table city) and then write things for multiple locations inside the city (to table details).
$sql="SELECT * FROM `details` as d INNER JOIN `city` as c ON d.city_details=c.city_id;";
if you want to look for a city name you can use this
$sql="SELECT * FROM `details` as d INNER JOIN `city` as c ON d.city_details=c.city_id WHERE c.cityName='The name you're looking for'";
then to fetch everyting from the table use this code
while($row=mysql_fetch_assoc(mysql_query($sql))){
echo $row['name']; //for name
echo $row['mytext']; //etc.
}
for more info see
http://dev.mysql.com/doc/refman/5.1/en/join.html
and
http://php.net/manual/en/function.mysql-fetch-assoc.php