Я новичок в создании собственных проектов и SQL в целом, и у меня возникли проблемы с наличием столбца «ранг», который будет генерировать рейтинг определенной строки данных на основе столбца «время». Я создаю полнофункциональную базу данных CRUD, которая извлекает информацию из базы данных MySQL в экспресс-интерфейс, и до сих пор я не могу понять, как выполнить функцию «поиска», которая возвращает строку, где name =? из пользовательского ввода при использовании функции ROW_NUMBER. Я все еще думаю, что иметь полностью отдельный столбец было бы идеально по сравнению с запуском запроса ROW_NUMBER каждый раз, когда я хочу найти результат поиска, но я понятия не имею, как бы это сделать.
Пока что моя функция поиска выглядит следующим образом:
async searchByName(name) {
try{
const response = await new Promise((resolve, reject) => {
const query = "SELECT *, ROW_NUMBER() OVER (ORDER BY time) rn FROM medley_relay; SELECT * FROM medley_relay WHERE name = ?;";
connection.query(query, [name], (err, results) => {
if (err) reject(new Error(err.message));
resolve(results);
})
});
console.info(response);
return response;
} catch (error) {
console.info(error);
}
}
Это называется так:
const {name} = request.params;
const db = dbService.getDbServiceInstance();
const result = db.searchByName(name);
result
.then(data => response.json({data : data}))
.catch(err => console.info(err));
console.info(result);
})
и отправлен на переднюю часть с этим:
searchBtn.onclick = function() {
const searchValue = document.querySelector('#search-input').value;
fetch('http://localhost:5000/search/' + searchValue)
.then(response => response.json())
.then(data => loadHTMLTable(data['data']));
}
loadHTMLTable — это
const table = document.querySelector('table tbody');
console.info(data);
if (data.length === 0) {
table.innerHTML = "<tr><td class='no-data'>No Data</td><td class = 'no-data'colspan='5'>No Data</td></tr>";
return;
}
let tableHtml = "";
data.forEach(function ({id, name, time, date, rn}) {
tableHtml += "<tr>";
tableHtml += `<td>${rn}</td>`;
tableHtml += `<td>${name}</td>`;
tableHtml += `<td>${time}</td>`;
tableHtml += `<td>${new Date(date).toLocaleDateString()}</td>`;
tableHtml += `<td><button class = "delete-row-btn" data-id=${id}>Delete</td>`;
tableHtml += `<td><button class = "edit-row-btn" data-id=${id}>Edit</td>`;
tableHtml += "</tr>";
});
table.innerHTML = tableHtml;
}
где у меня есть пользовательский ввод для искомого имени в виде элемента html в моем веб-приложении.
Взамен я получаю просто неопределенную таблицу для всех элементов, и когда я пытаюсь записать в console.info ответ, я получаю:
[
RowDataPacket {
id: 15,
name: 'Corning',
time: '01:40:15',
date: 2024-04-10T04:00:00.000Z,
rn: 1
},
RowDataPacket {
id: 16,
name: 'Binghamton',
time: '01:52:42',
date: 2024-04-02T04:00:00.000Z,
rn: 2
}
],
[
RowDataPacket {
id: 16,
name: 'Binghamton',
time: '01:52:42',
date: 2024-04-02T04:00:00.000Z
}
]
]
Еще раз прошу прощения, если это действительно просто, поскольку я впервые использую SQL или PHPmyadmin, но было бы здорово иметь специальный столбец, который будет номером строки, который будет автоматически обновляться при добавлении или удалении записей. До сих пор все остальные вещи, которые я нашел, основаны на ROW_NUMBER, который не создает постоянный столбец, по крайней мере, для меня, что не будет работать, поскольку мой «ранг» в конечном итоге не определен для моей таблицы.
Нет, автоматический постоянный столбец с номером строки невозможен.
Для этого есть несколько причин:
Если вы вставляете или удаляете одну строку в таблице с 1 миллиардом строк, действительно ли вам нужны накладные расходы на обновление номера строки в миллиарде строк? Большинство пользователей скажут нет. Это превратило бы простые операции в очень дорогостоящие.
Кроме того, если вы используете двоичный журнал в формате ROW, он будет копировать каждую обновленную строку в журнал.
MySQL поддерживает параллельные транзакции, поэтому номера строк могут быть разными для каждого сеанса. Если я вставляю несколько строк, но еще не зафиксировал новые строки, должна ли таблица перенумеровать строки? Возможно, в моем сеансе, но не в вашем, где вы находитесь в транзакции, просматривающей старое состояние таблицы. Возможно, вы даже вставили или удалили разные строки в своем сеансе, чего я в своем сеансе не вижу.
Любой запрос может включать JOIN
или UNION
, исключать строки из заданного результата на основании условий в предложении WHERE
или объединять несколько строк в меньшее количество строк на основе выражений GROUP BY
. Все это может изменить номера строк для данного результата запроса.
Если бы это было возможно, я бы ожидал, что это будет своего рода сгенерированный столбец.
Фактически, в документации по сгенерированным столбцам не говорится, что оконные функции запрещены.
@Бармар Попробуй. Вы получаете ОШИБКУ 3593 (HY000): в этом контексте нельзя использовать оконную функцию «номер_строки».
Я не удивлен, поскольку оконная функция во многом похожа на подзапрос. Правила по существу ограничивают создаваемый столбец одной и той же строкой. Так что это ошибка документации.
@Barmar dev.mysql.com/doc/refman/8.0/en/window-functions.html: «MySQL поддерживает оконные функции, которые для каждой строки запроса выполняют вычисления с использованием строк, связанных с этой строкой». Оконные функции основаны на наборах результатов запроса, а не на строках данной таблицы.
Предполагая, что время имеет индекс, и вы ожидаете получить только небольшое подмножество строк таблицы, вы можете проще всего вычислить ранг следующим образом:
select mr.*, 1+(select count(*) from medley_relay mr2 where mr2.time < mr.time) 'rank'
from medley_relay mr
where mr.name=?
(Для большей эффективности в таблице должен быть индекс времени.)
Это создает эквивалент функции Rank(), а не row_number() — ничьи получат одинаковый ранг. Если вместо этого вам нужен row_number и у вас есть pkid первичного ключа, сделайте where (mr2.time,mr2.pkid) < (mr.timr,mr.pkid)
. Для эквивалента плотности_ранга() измените на count(distinct mr2.time)
.
Почему вступление/союз имеет значение? Столбец должен быть рангом в таблице, а не рангом в запросе.