I have the following code:
$dbLink = mysql_connect('localhost', 'tester', 'test');
mysql_select_db('acianetm_pcSpec', $dbLink);
$q = $_GET['q'];
$q = mysql_real_escape_string($q);
$sql = "
SELECT *,
MATCH(part) AGAINST ('$q') AS score
FROM parts
WHERE MATCH(part) AGAINST('$q')
";
$rest = MySQL_query($sql);
while($row = MySQL_fetch_array($rest)) {
echo "<br /> <strong>".$row['id']. " - ". $row['part']. " - $". $row['price']."</strong>";
}
When I load up http://site.com/q?=Nvidia it does not display any output.
MySQL Structure:
CREATE TABLE `parts` (
`id` int(10) NOT NULL auto_increment,
`part` varchar(512) NOT NULL,
`price` varchar(15) NOT NULL,
`updated` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `part_2` (`part`),
FULLTEXT KEY `part` (`part`)
) ENGINE=MyISAM AUTO_INCREMENT=47 DEFAULT CHARSET=latin1
The data inside the table:
`id |#| part |#| price
46 |#| (VIC Clayton Clearance) GIGABYTE 9800GT 512MB Nvidia Geforce GF9800GT DVI P... |#| 95.00
I have tried this SQL query:
SELECT * FROM parts WHERE part LIKE '%$q%'
However without using str_replace eg.
str_replace(' ', '&'. $q); it never worked for multiple words. Using the str_replace only made it work with 2 words, I need multiple.
Doing this in PHPMyAdmin returns no rows either, so what part of the query is wrong?
If someone could assist that would be great.
Thanks alot
Omit the where clause in your sql statement.
Also the '?' in your URL should come before any name value pairs.
$sql = "SELECT * FROM parts
WHERE MATCH(part) AGAINST ('$q')";
Works well :-)
Related
(Spoiler: The Title has nothing to do with what is wrong with the code.)
I'm creating a live-search system just to show the user possible event types already listed on my website. During my speculations I may have an error with Wildcard binding which I'm unable to see.
I tried using different types of "WHERE LIKE" statements, and most of them didn't work at all. Such as I tried using placeholder query (question mark) and that did not work at all. If I ran this query manually on my database I will get results which I'm expecting.
This is how my code looks, the variable $q is obtained using $_GET method.
$query = $pdo->prepare('SELECT DISTINCT EventCategory FROM Events
WHERE EventCategory LIKE CONCAT(\'%\',:q,\'%\')');
$query->bindParam(":q", $q);
$query->execute();
$row = $query->fetch(PDO::FETCH_ASSOC);
while ($row = $query->fetchObject()) {
echo "<div> $row->EventCategory </div>";
}
The expected results would be: If the $q is equal to n, Meeting and Nightlife is returned. When $q is equal to ni, then Nightlife is only returned.
The search is NOT CASE SENSITIVE, N and n is treated equally.
The SHOW CREATE TABLE Events query returned the following:
CREATE TABLE `Events` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(100) NOT NULL,
`Image` varchar(600) NOT NULL,
`Date` date NOT NULL,
`Description` varchar(1200) NOT NULL,
`SpacesAvailable` int(11) NOT NULL,
`EventCategory` varchar(50) NOT NULL,
`Trending` varchar(30) DEFAULT NULL,
`TrendingID` int(255) NOT NULL,
`Sale` int(255) NOT NULL,
PRIMARY KEY (`ID`)
)DEFAULT CHARSET=latin1
Images to show the operation of the website: https://imgur.com/a/yP0hTm3
Please if you are viewing the images the view from bottom to top. Thanks
I suspect the default collation in your EventCategory column is case-sensitive. That's why Ni and ni don't match in Nightlife.
Try this query instead.
'SELECT DISTINCT EventCategory FROM Events WHERE EventCategory COLLATE utf8_general_ci LIKE CONCAT(\'%\',:q,\'%\')'
Or, if your column's character set is not unicode but rather iso8859-1, try this:
'SELECT DISTINCT EventCategory FROM Events WHERE EventCategory COLLATE latin1_general_ci LIKE CONCAT(\'%\',:q,\'%\')'
This explains how to look up the available character sets and collations on MySQL.
How to change collation of database, table, column? explains how to alter the default collation of a table or a column. It's generally a good idea because collations are baked into indexes.
The problem is not in LIKE, but in PHP and PDO. Stare at the 3 conflicting uses of $row in your code:
$row = $query->fetch(PDO::FETCH_ASSOC);
while ($row = $query->fetchObject()) {
echo "<div> $row->EventCategory </div>"; }
Then review the documentation and examples. (Sorry, I'm not going to feed you the answer; you need to study to understand it.)
In complement to the comprehensive answer by O.Jones, another, simpler solution would be to just perform a case-insensitive search, like :
'SELECT DISTINCT EventCategory
FROM Events
WHERE UPPER(EventCategory) LIKE CONCAT(\'%\',UPPER(:q),\'%\')'
I have 2 tables,one has 2 million and the other has 30 million records,
I need to compare the records on both tables but this is extremely slow.
can anyone offer suggestions on ways to increase the speed?
<?php
$con = mysql_connect("localhost","root","password");
mysql_select_db("DMBONE", $con);
$result = mysql_query("SELECT * FROM sucid where priority=''");
while($row = mysql_fetch_array($result))
{
$result1 = mysql_query("SELECT count(*) FROM bills_logic where month(tdate)=8 and x1=".$row[0]."");
if($row1 = mysql_fetch_array($result1))
{
if($row1[0]==0)
{
echo $row[0]." DEAD\r\n";
mysql_query("update sucid set priority='DEAD' where bid=".$row[0]."") or die(mysql_error());
}
else
{
echo $row[0]." ".$row1[0]."\r\n";
mysql_query("update sucid set priority='".$row1[0]."' where bid=".$row[0]."") or die(mysql_error());
}
}
}
?>
CREATE TABLE `sucid` (
`bid` varchar(500) NOT NULL,
`priority` varchar(500) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `bills_logic` (
`bid` int(11) NOT NULL AUTO_INCREMENT,
`num` varchar(500) NOT NULL,
`stat` varchar(500) NOT NULL,
`tdate` varchar(500) NOT NULL,
`x1` varchar(500) NOT NULL,
`amt` varchar(500) NOT NULL DEFAULT '30',
PRIMARY KEY (`bid`)
) ENGINE=InnoDB AUTO_INCREMENT=35214848 DEFAULT CHARSET=latin1
above are the create table statements for the tables.
You have found the world's slowest way of doing a join. You may be happier to do it the old-fashioned way (but just fashionably enough to use mysqli):
<?php
$mysqli = new mysqli("localhost","root","password","database");
if ($mysqli->connect_errno) {
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
$sql = "update sucid
left join (
select count(*) as priority, x1
from bills_logic b
where month(tdate)=8
group by x1
) bg
on bg.x1 = sucid.bid
set sucid.priority = coalesce(bg.priority,'DEAD');"
if ($mysqli->query($sql) === TRUE) {
printf("I'm done already. This was fast, wasn't it?\n");
}
else {
echo "Something went wrong: " . $mysqli->error . "\n";
exit();
}
?>
You might want to add an index on bills_logic.x1, though it will not help too much here.
And you should really fix your columns, e.g. tdate should not be a varchar(500). The update will fail completely if you have any row with an invalid date. Using correct datatypes prevents you from having invalid values. num, stat and amt sound like they could be int (or maybe decimal), x1 maybe too. And your priority-column would also work as int, if you replace DEAD with 0.
Yeah it is possible that you have a big big problem on it. The speed and query performance depends on:
Database schema table structure.
Machine hardware specs.
Your query structure.
table Indexes.
Hope all Database expert do not include the blob at the same table which is the primary table. this is the big problem of all database when we talk about a million of data to fetch on. Much better to separate the blob data always as best practice.
This is just additional info, Hope it could help the others.
I would suggest to create indexes, particularly for the values that you are using to delimitate your searches. In your particular case, I would start by creating an index for the field priority.
For more info on how mysql deals with indexes take a look here.
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.
I have mysql table as follows;
CREATE TABLE IF NOT EXISTS `cheque_data` (
`auto_no` int(11) NOT NULL AUTO_INCREMENT,
`job_no` int(11) NOT NULL,
`client_id` text NOT NULL,
`ch_no` text NOT NULL,
`ch_date` date NOT NULL,
`ch_bank` text NOT NULL,
`ch_amount` decimal(10,2) NOT NULL,
`sync` int(1) NOT NULL DEFAULT '0',
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`auto_no`)
)
When I run SQL command in PHPMYADMIN it will retrieve row;
SELECT * FROM `cheque_data` WHERE timestamp='2014-03-10 19:37:31'.
But in PHP,
$sql = "select * from `cheque_data` where timestamp = '2014-03-10 19:37:31'";
$result_remote = mysqli_query($con,$sql) or die(mysqli_error($con));
$row_count = mysqli_num_rows($result_remote);
echo $row_count; //no data
It doesn't give any data. But when I change timestamp to other column, it works.
$sql = "select * from `cheque_data` where auto_no = '1'";
$result_remote = mysqli_query($con,$sql) or die(mysqli_error($con));
$row_count = mysqli_num_rows($result_remote);
echo $row_count; //data found
I want to know, what is the reason for this issue?
It is only not working with where timestamp
Thank you,
Sameera
add backticks(`) around timestamp field, as it is reserved word or use this query
$sql = "select * from `cheque_data` where `timestamp` = '2014-03-10 19:37:31'";
Possibly, the problem in your PHP script, not MySQL.
P.S. keep in mind, that it is better to wrap column names in ` not to confuse MySQL. In your statement it is okay, but fyi there is a function called TIMESTAMP(), and in some cases MySQL may think of a non-wraped column name as of a function name.
I'm dealing with this problem. There is tableorders(oid,datetime,quantity,title,username,mid).
The table orders is updated from php code as far as the features oid,datetime,quantity,title,username are concerned. The problem is that I want to classify each entry based on both datetime and username so as to gather these entries under an order code in order to make an ordering entry. (I can't think of anything else at the moment).
The question is how can I select those entries that are corresponding to the same username and the same date time.
For example the if I have 3entries (freddo espresso,latte,freddoccino) belong to the same order procedure (are posted by the same username, tha exact same datetime) and I need to present them to my user as a completed order.
Here is the structure of table orders:
CREATE TABLE IF NOT EXISTS `orders` (
`oid` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`datetime` DATETIME NOT NULL,
`quantity` INT NOT NULL,
`sum` FLOAT(4,2) NOT NULL,
`title` VARCHAR(30) COLLATE utf8_unicode_ci NOT NULL,
`username` VARCHAR(30) COLLATE utf8_unicode_ci NOT NULL,
`mid` VARCHAR(30) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`oid`),
KEY `username`(`username`,`mid`,`title`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=10000;
The feature title is foreign key from table products:
CREATE TABLE IF NOT EXISTS `products`(
`title` VARCHAR(30) COLLATE utf8_unicode_ci NOT NULL,
`descr` TEXT(255),
`price` FLOAT(4,2) NOT NULL,
`popularity` INT NOT NULL,
`cname` VARCHAR(20) COLLATE utf8_unicode_ci NOT NULL,
`mid` VARCHAR(30) COLLATE utf8_unicode_ci NOT NULL ,
PRIMARY KEY(`title`),
KEY `cname` (`cname`, `mid`)
)ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=10000;
Sorry If I'm a little uncomprehensive, though I really need some help to come to a conclusion. Any ideas?
Thanks in advance!
If you know what the datetime value and the username values are then you can simply use:
SELECT * FROM orders WHERE username = '$username' AND datetime = '$datetime'
However, what you would be better off doing is splitting this into two separate tables; something like:
Orders
OrderID
OrderTime
UserName
Items
ItemID
OrderID
Title
Then you would search in the following way:
SELECT Orders.OrderID, Orders.UserName, Items.Title
FROM Orders
INNER JOIN Items ON Orders.OrderID = Items.OrderID
WHERE
Orders.UserName = '$username'
AND
Orders.OrderDate = '$datetime'
When adding orders you add a record to Orders first, and then use that OrderID and add it to each item inserted in Items...
Insert Example
$mysqli; //Assuming your connection to the database...
$items; //Assuming an array of items for the order like: array('Coffee', 'Tea')
$username; //Assuming the user name to be inserted for the order
$mysqli->query("INSERT INTO Orders(`OrderTime`, `UserName`) VALUES(NOW(), '$username')");
$orderid = $mysqli->insert_id;
foreach($items as $item){
$mysqli->query("INSERT INTO Items (`OrderID`, `Title`) VALUES($orderid, '$title')");
}
NOTE: You should make sure to sanitize data before inserting to database...
Storing JSON
Storing JSON in a database is going to require you to make sure that you use a field data type that is an appropriate length (e.g. a blob).
You mentioned that you retrieve the titles as an array from a form so I'm now going to refer to that as $titles.
Saving to database
$username = '...'; // Username or id to store in database with order
$titles = array(.....); // Array of titles from form
$encodedTitles = json_encode($titles); // Convert to JSON
$mysqli->query("INSERT INTO table_name (titles_field, username_field, date_field) VALUES ('$titles', '$username', NOW())"); // Save to database (assuming already open connection
Retrieve from database
$result = $mysqli->query("SELECT titles FROM table_name WHERE username = 'username_value' AND date_field = 'date_value'"); //Run query to get row
$row = $result->fetch_assoc(); // Fetch row
$titles = json_decode($row['titles']); // This is the same as the `titles` array from the from above!
SELECT quantity,title
FROM orders
WHERE username = ? and datetime = ?
Would return the quantity of items for a specific user on specific date. Instead of a date you could use an order id, which might be a bit safer. If you use order id, then username becomes irrelevant as well, since order ids should be unique.
The answer posted with the query will help you but you should also consider changing your table structure. Looks like you could have a table named orders and another one named orders_items. Then you could list all the itens from orders_itens matching a single order.
I think this query will return kind of data where you have the same unique_id string for records where username and datetime are the same.
SELECT MD5(a.unique_id), b.* FROM (
SELECT
GROUP_CONCAT(oid) unique_id, `datetime`, username
FROM `orders` GROUP BY username, `datetime`
) a
RIGHT JOIN `orders` b
ON a.`datetime` = b.`datetime` AND a.username = b.username
ORDER BY unique_id, oid;
I also have another answer for about 3 thousands characters long but I think this variant will help you more than my long tutorial how to split the table to two tables and how to migrate data into it + php code samples. So I decided not publicate it. )))
Edit: I think you even can run this one query which is easiest and works faster:
SELECT *, MD5( CONCAT( `username` , `datetime` ) ) unique_id
FROM `orders`
ORDER BY unique_id, oid;