Результат БД упорядочен по ближайшим совпадениям (3 числовых критерия)

Я пытаюсь создать систему, в которой я могу вводить несколько значений и получать все совпадения с допуском 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% во всех значениях.

Если бы это был я, я бы начал с sql

Strawberry 18.12.2020 18:13

Привет! Что ты имеешь в виду? спасибо

Federico Scalise Giussani 18.12.2020 18:16

Как вы определяете «мне нужно получить наилучшее совпадение сверху»?

Felippe Duarte 18.12.2020 18:19

См. Почему я должен предоставлять MCRE для того, что мне кажется очень простым SQL-запросом

Strawberry 18.12.2020 18:26

@FelippeDuarte, я имею в виду, что у меня есть строки, которые лучше всего соответствуют введенным числам! На изображении вы можете видеть, что я имею в виду.

Federico Scalise Giussani 18.12.2020 18:28

@Strawberry, я поработаю над этим, чтобы получить что-нибудь для тебя!

Federico Scalise Giussani 18.12.2020 18:28

Хорошо, но что для вас означает «лучшее совпадение»?

Felippe Duarte 18.12.2020 18:36

@Strawberry, это будут данные, которые у меня есть в моей таблице: sqlfiddle.com/#!9/6e705f Так что, если мне нужен, например, продукт с L = 95, A = 95 и H = 95, Я хотел бы, чтобы сначала отображался BAT 3, а затем BAT 2 и BAT 1. Но не BAT 4, потому что он не находится в допуске 15% для всех значений.

Federico Scalise Giussani 18.12.2020 18:36

@FelippeDuarte, это будет строка с ближайшими значениями к входным данным!

Federico Scalise Giussani 18.12.2020 18:37

Предупреждение: вы широко открыты для SQL-инъекций и должны использовать параметризованные подготовленные операторы, а не создавать запросы вручную. Они предоставляются PDO или MySQLi . Никогда не доверяйте никаким данным! Даже когда ваши запросы выполняются только доверенными пользователями, вы все равно рискуете повредить свои данные . Сбежать недостаточно!

Dharman 18.12.2020 18:43

@Дхарман! Я единственный, кто собирается использовать это, так что не так уж важно защитить скрипт. Но спасибо за рекомендацию!!

Federico Scalise Giussani 18.12.2020 18:57

Это не имеет значения. Даже вы можете случайно сломать сайт из-за этого. Пожалуйста, не пренебрегайте этим. Нет абсолютно никаких причин, по которым вы не должны использовать подготовленные операторы. Пожалуйста, научитесь делать это правильно с самого начала, и это избавит вас от многих проблем позже.

Dharman 18.12.2020 19:00

@Dharman, я последую твоему совету! Когда я решу эту проблему, я преобразую все в подготовленные операторы!

Federico Scalise Giussani 18.12.2020 19:06

Пожалуйста, отредактируйте свой вопрос соответствующим образом - эта информация слишком ценна, чтобы ее можно было похоронить в комментариях.

Strawberry 18.12.2020 19:08

Ваш запрос выглядит хорошо, но я не понимаю правил определения приоритетов результатов.

Strawberry 18.12.2020 19:20

Этот запрос даст мне результаты в том порядке, в котором они были сохранены. Я не хочу этого! Мне нужно, чтобы получить результат с ближайшими значениями к входу сверху, а затем остальные. Спасибо

Federico Scalise Giussani 18.12.2020 19:31

Но вы не определяете «ближайший»

Strawberry 18.12.2020 21:54

Итак, если вы запросите 90-90-90 и получите результаты 85-85-85, 95-95-95 и 85-100-90, что ближе всего?

Felippe Duarte 18.12.2020 22:00

@FelipeDuarte, в таком случае все они будут работать! Порядок там не имел бы значения!

Federico Scalise Giussani 18.12.2020 22:56

Я удалил теги JavaScript и jQuery для вопроса.

Louys Patrice Bessette 18.12.2020 23:16
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout.
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout.
Laravel Scout - это популярный пакет, который предоставляет простой и удобный способ добавить полнотекстовый поиск в ваше приложение Laravel. Он...
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для...
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для...
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
1
20
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Давайте сначала исправим вашу проблему с 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 ассоциативному массиву: И обратите внимание:

    1. Использование BETWEEN здесь, что является хорошей альтернативой сравнениям, которые вы использовали (чтобы было понятнее).
    1. Заполнители ? для привязки значений через параметрический механизм подготовленных операторов.

$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 с использованием этой сортировки (с поддельным ассоциативным массивом).

Большое спасибо! Я не дома рп, но я попробую как можно скорее и обновлю вас!

Federico Scalise Giussani 18.12.2020 22:53

Другие вопросы по теме

SQL Как получить среднее значение в день
Есть ли способ избежать ошибок при выполнении миграций при работе с Laravel?
Выберите полную строку с последним полем даты и времени после некоторых «левых соединений»
Код ошибки: 1062. Повторяющаяся запись для ключа Уникальное поле данных с использованием ОБНОВЛЕНИЯ. MySQL
Получение данных из 2 таблиц с отношением «один ко многим» с использованием лимита и смещения в «главной» таблице
SQL Выберите одни и те же столбцы из двух разных таблиц
Каков наилучший способ запросить эту таблицу «Отдел-Сотрудник», чтобы получить отдел, в котором есть точные сотрудники?
Скрыть кнопку удаления из таблицы через 3 дня
Объедините повторяющиеся строки с одинаковыми значениями в двух столбцах моей таблицы mysql и добавьте значения в третий столбец.
Проверка пользовательского ввода с использованием регулярного выражения для предотвращения инъекции sql