Я пытаюсь создать систему, в которой я могу вводить несколько значений и получать все совпадения с допуском 15% из таблицы mysql. Я сделал макет в HTML и CSS, и мне удалось добиться этого, но проблема в том, что мне нужно получить наилучшее соответствие сверху!
В моей таблице 4 столбца Modelo, L, A, H (модель, длина, ширина, высота) Вот мой код: HTML
<div class = "battrac">
<label for = "largo">L</label>
<input id = "largo" name = "largo" onkeyup = "buscar()" required></input>
<label for = "ancho">A</label>
<input id = "ancho" name = "ancho" onkeyup = "buscar()" required></input>
<label for = "alto">H</label>
<input id = "alto" name = "alto" onkeyup = "buscar()" required></input>
</div>
JS
function buscar() {
// if (str= = "") {
// document.getElementById("result-trac").innerHTML = "";
// }
var l = document.getElementById("largo").value;
var a = document.getElementById("ancho").value;
var h = document.getElementById("alto").value;
var xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function() {
if (this.readyState==4 && this.status==200) {
document.getElementById("result-trac").innerHTML=this.responseText;
}
}
xmlhttp.open("GET","busc.php?t = "+tipo+"&l = "+l+"&a = "+a+"&h = "+h,true);
xmlhttp.send();
}
Busc.php
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$link = mysqli_connect("localhost", "root", "", "test");
if ($link === false){
die("ERROR: Could not connect. " . mysqli_connect_error());
}
$l = $_GET['l'];
$a = $_GET['a'];
$h = $_GET['h'];
if ($l= = "" ||$a= = "" ||$h= = ""){
echo("Por favor compelte todos los campos");
exit;
}
$sql = "SELECT * FROM test WHERE L>=($l * .85) AND L<=($l * 1.15) AND A>=($a * .85) AND A<=($a * 1.15) AND H>=($h * .85) AND H<=($h * 1.15)";
$result = $link->query($sql);
if ($result->num_rows > 0) {
echo('<table style = "width:100%">
<tr>
<th>Modelo</th>
<th>L</th>
<th>A</th>
<th>H</th>
</tr>');
while($row = $result->fetch_assoc()) {
echo("
<tr>
<td>".$row['Producto']."</td>
<td>".$row['L']."</td>
<td>".$row['A']."</td>
<td>".$row['H']."</td>
</tr>
");
}
echo('</table>');
}else{echo($link->connect_error);}
?>
На этом рисунке ближайшим совпадением является BAT 2, но BAT 1 появляется первым.
Некоторые идентификаторы и классы указаны на испанском языке, но если вам нужна какая-либо другая информация, дайте мне знать! Обновлено: Что мне нужно сделать, так это получить ближайшее совпадение сверху. См. на рисунке BAT 2 имеет больше близких чисел, чем BAT 1 Дора, но BAT 1 находится наверху. Я хочу, чтобы BAT 2 отображался сверху Вот рабочий пример с 4 строками http://sqlfiddle.com/#!9/6e705f Итак, если мне нужен, например, продукт с L=95, A=95 и H=95, я хотел бы чтобы сначала отображался BAT 3, а затем BAT 2 и BAT 1. Но не BAT 4, потому что он не находится в допуске 15% во всех значениях.
Привет! Что ты имеешь в виду? спасибо
Как вы определяете «мне нужно получить наилучшее совпадение сверху»?
См. Почему я должен предоставлять MCRE для того, что мне кажется очень простым SQL-запросом
@FelippeDuarte, я имею в виду, что у меня есть строки, которые лучше всего соответствуют введенным числам! На изображении вы можете видеть, что я имею в виду.
@Strawberry, я поработаю над этим, чтобы получить что-нибудь для тебя!
Хорошо, но что для вас означает «лучшее совпадение»?
@Strawberry, это будут данные, которые у меня есть в моей таблице: sqlfiddle.com/#!9/6e705f Так что, если мне нужен, например, продукт с L = 95, A = 95 и H = 95, Я хотел бы, чтобы сначала отображался BAT 3, а затем BAT 2 и BAT 1. Но не BAT 4, потому что он не находится в допуске 15% для всех значений.
@FelippeDuarte, это будет строка с ближайшими значениями к входным данным!
Предупреждение: вы широко открыты для SQL-инъекций и должны использовать параметризованные подготовленные операторы, а не создавать запросы вручную. Они предоставляются PDO или MySQLi . Никогда не доверяйте никаким данным! Даже когда ваши запросы выполняются только доверенными пользователями, вы все равно рискуете повредить свои данные . Сбежать недостаточно!
@Дхарман! Я единственный, кто собирается использовать это, так что не так уж важно защитить скрипт. Но спасибо за рекомендацию!!
Это не имеет значения. Даже вы можете случайно сломать сайт из-за этого. Пожалуйста, не пренебрегайте этим. Нет абсолютно никаких причин, по которым вы не должны использовать подготовленные операторы. Пожалуйста, научитесь делать это правильно с самого начала, и это избавит вас от многих проблем позже.
@Dharman, я последую твоему совету! Когда я решу эту проблему, я преобразую все в подготовленные операторы!
Пожалуйста, отредактируйте свой вопрос соответствующим образом - эта информация слишком ценна, чтобы ее можно было похоронить в комментариях.
Ваш запрос выглядит хорошо, но я не понимаю правил определения приоритетов результатов.
Этот запрос даст мне результаты в том порядке, в котором они были сохранены. Я не хочу этого! Мне нужно, чтобы получить результат с ближайшими значениями к входу сверху, а затем остальные. Спасибо
Но вы не определяете «ближайший»
Итак, если вы запросите 90-90-90 и получите результаты 85-85-85, 95-95-95 и 85-100-90, что ближе всего?
@FelipeDuarte, в таком случае все они будут работать! Порядок там не имел бы значения!
Я удалил теги JavaScript и jQuery для вопроса.
Давайте сначала исправим вашу проблему с SQL-инъекцией. В busc.php вы уже используете mysqli_connect, и это хорошо.
Проблема заключается в передаче значений GET непосредственно в запросе SQL. Так что вам нужно "подготовленное заявление". Вот подробный мастер-класс.
Но перед этим... И помимо проблемы с SQL-инъекцией, вы, безусловно, захотите убедиться, что значения являются числовыми, чтобы правильно запрашивать БД. Поэтому я предлагаю вам применить эту логику к 3 переменным GET:
if (isset($_GET['l']) && is_numeric($_GET['l'])) {
$l= (int) $_GET['l'];
} else {
$l= 100; // Default value if unset or non-numeric
}
Теперь попробуйте этот mysqli подготовленный оператор, который приведет к $rows ассоциативному массиву: И обратите внимание:
?
для привязки значений через параметрический механизм подготовленных операторов.$query = 'SELECT * FROM test WHERE
L BETWEEN (? * .85) AND (? * 1.15) AND
A BETWEEN (? * .85) AND (? * 1.15) AND
H BETWEEN (? * .85) AND (? * 1.15)';
$stmt = $link->prepare($query);
$stmt->bind_param("iiiiii", $l, $l, $a, $a, $h, $h); // iiiiii means 6 integers
$stmt->execute();
$rows = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
$stmt->close();
Вот SQLFiddle об этом BETWEEN использовании.
Итак, теперь результаты БД извлекаются, и соединение закрывается. У вас есть ассоциативный массив $rows, который еще не отсортирован так, как вы хотите... Над этим массивом нужно проделать дополнительную работу, и это был ваш главный вопрос.
В каждую «строку» этого $rows... Добавьте дополнительный элемент массива для хранения суммы абсолютной разницы каждого значения. Это будет использоваться для упорядочения строк в таблице.
for($i=0;$i<sizeOf($rows);$i++){
$L = abs($rows[$i]['L']-$l);
$A = abs($rows[$i]['A']-$a);
$H = abs($rows[$i]['H']-$h);
$diff = $L + $A + $H;
$rows[$i]["diff"] = $diff;
}
Для $row[$i] как ["L"=>90, "H"=>100, "A"=>95] и отправленных значений 100 для всех 3 переменных $l, $a и $h $diff будет 15.
Итак, теперь вы будете сортировать $rows на основе значений $diff... Спасибо , который ТАК ответил о том, как фильтровать массив на основе значения подмассива.
// Sorting sub array SO answer: https://stackoverflow.com/a/2477524/2159528
usort($rows, function ($a, $b) {
return $a['diff'] <=> $b['diff'];
});
И, наконец... Эхо по таблице:
echo('
<table style = "width:100%">
<tr>
<th>Modelo</th>
<th>L</th>
<th>A</th>
<th>H</th>
<th>diff</th> <!-- Added for debugging... Don't show it! -->
</tr>
');
for($i=0;$i<sizeOf($rows);$i++){ // Loop the "ordered" rows
echo('
<tr>
<td>'.$rows[$i]['Producto'].'</td>
<td>'.$rows[$i]['L'].'</td>
<td>'.$rows[$i]['A'].'</td>
<td>'.$rows[$i]['H'].'</td>
<td>'.$rows[$i]['diff'].'</td> <!-- Added for debugging... Don't show it! -->
</tr>
');
}
echo '</table>';
Я сделал PhpFiddle (нажал F9 или кнопку RUN), показывающий, что таблица будет упорядочена на основе $diff с использованием этой сортировки (с поддельным ассоциативным массивом).
Большое спасибо! Я не дома рп, но я попробую как можно скорее и обновлю вас!
Если бы это был я, я бы начал с sql