Вместо того, чтобы бросать код на вас, есть два понятия, которые являются ключом к пониманию того, как JS обрабатывает обратные вызовы и асинхронность. (это даже слово?)
Есть три вещи, о которых вам нужно знать; Очередь; цикл события и стек
. В широких упрощенных терминах цикл событий подобен диспетчеру проекта, он постоянно прослушивает любые функции, которые хотят запускать и взаимодействовать между очереди и стека.
while (queue.waitForMessage()) {
queue.processNextMessage();
}
Как только он получает сообщение для запуска чего-то, он добавляет его в очередь. Очередь - это список вещей, которые ждут выполнения (например, ваш запрос AJAX). Представьте себе это так:
1. call foo.com/api/bar using foobarFunc
2. Go perform an infinite loop
... and so on
Когда одно из этих сообщений будет исполнено, оно выталкивает сообщение из очереди и создает стек, стек - это все, что нужно выполнить JS для выполнения инструкции в сообщение. Таким образом, в нашем примере ему говорят позвонить foobarFunc
function foobarFunc (var) {
console.log(anotherFunction(var));
}
. Так что все, что foobarFunc должно выполнить (в нашем случае anotherFunction
), будет вставлено в стек. исполняемый, а затем забытый - цикл события затем переместится на следующую вещь в очереди (или прослушивает сообщения)
. Главное здесь - порядок выполнения. Это
Когда вы совершаете вызов с использованием AJAX для внешней стороны или выполняете любой асинхронный код (например, setTimeout), Javascript зависит от ответ, прежде чем он сможет продолжить.
Большой вопрос, когда он получит ответ? Ответ в том, что мы не знаем, поэтому цикл событий ждет, когда это сообщение скажет: «Эй, забери меня». Если JS просто ждал этого сообщения синхронно, ваше приложение замерзнет, и оно сосать. Таким образом, JS продолжает выполнение следующего элемента в очереди, ожидая, пока сообщение не будет добавлено обратно в очередь.
Вот почему с асинхронной функциональностью мы используем вещи, называемые обратными вызовами. Это похоже на обещание буквально. Как и в I , обещание что-то вернуть в какой-то момент jQuery использует специальные обратные вызовы, называемые deffered.done
deffered.fail
и deffered.always
(среди других). Вы можете увидеть их все здесь
Итак, вам нужно передать функцию, которая в какой-то момент будет выполнена с переданными ей данными.
Поскольку обратный вызов не выполняется немедленно, но в более позднее время важно передать ссылку на функцию, которую она не выполнила. поэтому
function foo(bla) {
console.log(bla)
}
, поэтому большую часть времени (но не всегда) вы пройдете foo
не foo()
. Надеюсь, это будет иметь смысл. Когда вы сталкиваетесь с такими вещами, которые кажутся запутанными, я настоятельно рекомендую полностью прочитать документацию, чтобы хотя бы понять ее. Это сделает вас намного лучшим разработчиком.
Я бы определил функцию:
delimiter $$
DROP FUNCTION IF EXISTS `getFakeId`$$
CREATE FUNCTION `getFakeId`() RETURNS int(11)
DETERMINISTIC
begin
return if(@fakeId, @fakeId:=@fakeId+1, @fakeId:=1);
end$$
, тогда я мог бы сделать:
select getFakeId() as id, t.* from table t, (select @fakeId:=0) as t2;
Теперь у вас нет подзапроса, который у вас не может быть в просмотров.
Я также проголосую за решение Мости Мостачо с незначительной модификацией его кода запроса:
SELECT a.i, a.j, (
SELECT count(*) from test b where a.j >= b.j AND a.i = b.i
) AS row_number FROM test a
Что даст тот же результат:
+------+------+------------+
| i | j | row_number |
+------+------+------------+
| 1 | 11 | 1 |
| 1 | 12 | 2 |
| 1 | 13 | 3 |
| 2 | 21 | 1 |
| 2 | 22 | 2 |
| 2 | 23 | 3 |
| 3 | 31 | 1 |
| 3 | 32 | 2 |
| 3 | 33 | 3 |
| 4 | 14 | 1 |
+------+------+------------+
для таблицы:
+------+------+
| i | j |
+------+------+
| 1 | 11 |
| 1 | 12 |
| 1 | 13 |
| 2 | 21 |
| 2 | 22 |
| 2 | 23 |
| 3 | 31 |
| 3 | 32 |
| 3 | 33 |
| 4 | 14 |
+------+------+
С той лишь разницей, что запрос не использует JOIN и GROUP BY, вместо этого полагается на вложенный выбор.
Это позволяет использовать те же функции, что и ROW_NUMBER () AND PARTITION BY в MySQL
SELECT @row_num := IF(@prev_value=GENDER,@row_num+1,1) AS RowNumber
FirstName,
Age,
Gender,
@prev_value := GENDER
FROM Person,
(SELECT @row_num := 1) x,
(SELECT @prev_value := '') y
ORDER BY Gender, Age DESC
Немного поздно, но может помочь и тем, кто ищет ответы ...
Между строками / row_number example - рекурсивный запрос, который может использоваться в любом SQL:
WITH data(row_num, some_val) AS
(
SELECT 1 row_num, 1 some_val FROM any_table --dual in Oracle
UNION ALL
SELECT row_num+1, some_val+row_num FROM data WHERE row_num < 20 -- any number
)
SELECT * FROM data
WHERE row_num BETWEEN 5 AND 10
/
ROW_NUM SOME_VAL
-------------------
5 11
6 16
7 22
8 29
9 37
10 46
SELECT
@i:=@i+1 AS iterator,
t.*
FROM
tablename AS t,
(SELECT @i:=0) AS foo
Ознакомьтесь с этой статьей, она показывает, как имитировать SQL ROW_NUMBER () с разделом в MySQL. Я столкнулся с тем же самым сценарием в реализации WordPress. Мне нужен ROW_NUMBER (), и его там не было.
http://www.explodybits.com/2011/11/mysql-row-number/
В примере в статье используется один разделять по полю. Чтобы разделить дополнительные поля, вы можете сделать что-то вроде этого:
SELECT @row_num := IF(@prev_value=concat_ws('',t.col1,t.col2),@row_num+1,1) AS RowNumber
,t.col1
,t.col2
,t.Col3
,t.col4
,@prev_value := concat_ws('',t.col1,t.col2)
FROM table1 t,
(SELECT @row_num := 1) x,
(SELECT @prev_value := '') y
ORDER BY t.col1,t.col2,t.col3,t.col4
Использование concat_ws обрабатывает null. Я проверил это на 3 поля, используя int, date и varchar. Надеюсь это поможет. Просмотрите статью, так как она нарушает этот запрос и объясняет это.
Это также может быть решением:
SET @row_number = 0;
SELECT
(@row_number:=@row_number + 1) AS num, firstName, lastName
FROM
employees
Это отлично работает для меня, чтобы создать RowNumber, когда у нас есть несколько столбцов. В этом случае две колонки.
SELECT @row_num := IF(@prev_value= concat(`Fk_Business_Unit_Code`,`NetIQ_Job_Code`), @row_num+1, 1) AS RowNumber,
`Fk_Business_Unit_Code`,
`NetIQ_Job_Code`,
`Supervisor_Name`,
@prev_value := concat(`Fk_Business_Unit_Code`,`NetIQ_Job_Code`)
FROM (SELECT DISTINCT `Fk_Business_Unit_Code`,`NetIQ_Job_Code`,`Supervisor_Name`
FROM Employee
ORDER BY `Fk_Business_Unit_Code`, `NetIQ_Job_Code`, `Supervisor_Name` DESC) z,
(SELECT @row_num := 1) x,
(SELECT @prev_value := '') y
ORDER BY `Fk_Business_Unit_Code`, `NetIQ_Job_Code`,`Supervisor_Name` DESC
Из MySQL 8.0.0
и выше вы можете использовать оконные функции.
Функции окна ,
MySQL теперь поддерживает функции окна, которые для каждой строки из запроса выполняют вычисление с использованием строк, относящихся к этой строке. К ним относятся такие функции, как RANK (), LAG () и NTILE (). Кроме того, в качестве функций окна можно использовать несколько существующих совокупных функций; (g7) ROW_NUMBER () over_clause :
Возвращает номер текущего строка внутри своего раздела. Номера строк варьируются от 1 до количества строк раздела.
ORDER BY влияет на порядок, в котором строки нумеруются. Без ORDER BY нумерация строк является неопределенной.
blockquote>Демо:
CREATE TABLE Table1( id INT AUTO_INCREMENT PRIMARY KEY, col1 INT,col2 INT, col3 TEXT); INSERT INTO Table1(col1, col2, col3) VALUES (1,1,'a'),(1,1,'b'),(1,1,'c'), (2,1,'x'),(2,1,'y'),(2,2,'z'); SELECT col1, col2,col3, ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow FROM Table1;
В MySQL нет функции, такой как rownum
, row_num()
, но путь примерно такой:
select
@s:=@s+1 serial_no,
tbl.*
from my_table tbl, (select @s:=0) as s;
Также немного поздно, но сегодня у меня была такая же потребность, поэтому я искал в Google и, наконец, простой общий подход, найденный здесь в статье Pinal Dave http://blog.sqlauthority.com/2014/03/09 / mysql-reset-row-number-for-each-group-partition-by-row-number /
Я хотел сосредоточиться на первоначальном вопросе Павла (это тоже моя проблема) поэтому я обобщаю свое решение как рабочий пример.
Beacuse мы хотим разделить на два столбца, я бы создал переменную SET во время итерации, чтобы определить, была ли запущена новая группа.
SELECT col1, col2, col3 FROM (
SELECT col1, col2, col3,
@n := CASE WHEN @v = MAKE_SET(3, col1, col2)
THEN @n + 1 -- if we are in the same group
ELSE 1 -- next group starts so we reset the counter
END AS row_number,
@v := MAKE_SET(3, col1, col2) -- we store the current value for next iteration
FROM Table1, (SELECT @n := 0, @v := NULL) r -- helper table for iteration with startup values
ORDER BY col1, col2, col3 DESC -- because we want the row with maximum value
) x WHERE row_number = 1 -- and here we select exactly the wanted row from each group
Средство 3 при первом параметре MAKE_SET, которое я хочу, имеет значение в SET (3 = 1 | 2). Конечно, если у нас нет двух или более столбцов, строящих группы, мы можем исключить операцию MAKE_SET. Конструкция точно такая же. Это работает для меня, как требуется. Большое спасибо Пиналу Дейву за его четкую демонстрацию.
Я всегда заканчиваю этот шаблон. Учитывая эту таблицу:
+------+------+
| i | j |
+------+------+
| 1 | 11 |
| 1 | 12 |
| 1 | 13 |
| 2 | 21 |
| 2 | 22 |
| 2 | 23 |
| 3 | 31 |
| 3 | 32 |
| 3 | 33 |
| 4 | 14 |
+------+------+
Вы можете получить этот результат:
+------+------+------------+
| i | j | row_number |
+------+------+------------+
| 1 | 11 | 1 |
| 1 | 12 | 2 |
| 1 | 13 | 3 |
| 2 | 21 | 1 |
| 2 | 22 | 2 |
| 2 | 23 | 3 |
| 3 | 31 | 1 |
| 3 | 32 | 2 |
| 3 | 33 | 3 |
| 4 | 14 | 1 |
+------+------+------------+
Запустив этот запрос, который не нуждается в какой-либо переменной:
SELECT a.i, a.j, count(*) as row_number FROM test a
JOIN test b ON a.i = b.i AND a.j >= b.j
GROUP BY a.i, a.j
Надеюсь, что это поможет!
В MySQL нет рейтинговой функциональности. Самое близкое, что вы можете получить, это использовать переменную:
SELECT t.*,
@rownum := @rownum + 1 AS rank
FROM YOUR_TABLE t,
(SELECT @rownum := 0) r
, и как это будет работать в моем случае? Мне нужны две переменные: по одному для каждого из col1 и col2? Col2 нужно будет как-то сбросить, когда col1 изменится.?
blockquote>Да. Если бы это был Oracle, вы могли бы использовать функцию LEAD для достижения пика при следующем значении. К счастью, Quassnoi охватывает логику того, что вам нужно реализовать в MySQL .
MariaDB 10.2 реализует «Функции окна», включая RANK (), ROW_NUMBER () и несколько других вещей:
https://mariadb.com/kb/en/mariadb/window -функции /
Основываясь на разговоре в Percona Live в этом месяце, они достаточно хорошо оптимизированы.
Синтаксис идентичен коду в Вопросе.
Я не вижу никакого простого ответа, охватывающего часть «PARTITION BY», поэтому вот мой:
SELECT
*
FROM (
select
CASE WHEN @partitionBy_1 = l THEN @row_number:=@row_number+1 ELSE @row_number:=1 END AS i
, @partitionBy_1:=l AS p
, t.*
from (
select @row_number:=0,@partitionBy_1:=null
) as x
cross join (
select 1 as n, 'a' as l
union all
select 1 as n, 'b' as l
union all
select 2 as n, 'b' as l
union all
select 2 as n, 'a' as l
union all
select 3 as n, 'a' as l
union all
select 3 as n, 'b' as l
) as t
ORDER BY l, n
) AS X
where i > 1
CASE WHEN @partitionBy_1 = part1 AND @partitionBy_2 = part2 [...] THEN @row_number:=@row_number+1 ELSE @row_number:=1 END AS i
, @partitionBy_1:=part1 AS P1
, @partitionBy_2:=part2 AS P2
[...]
FROM (
SELECT @row_number:=0,@partitionBy_1:=null,@partitionBy_2:=null[...]
) as x
запрос для row_number в mysql
set @row_number=0;
select (@row_number := @row_number +1) as num,id,name from sbs
Решение, которое я нашел лучшим, это использовать подзапрос, подобный этому:
SELECT
col1, col2,
(
SELECT COUNT(*)
FROM Table1
WHERE col1 = t1.col1
AND col2 = t1.col2
AND col3 > t1.col3
) AS intRow
FROM Table1 t1
Столбцы PARTITION BY просто сравниваются с '=' и разделяются символом AND. Столбцы ORDER BY будут сравниваться с '& lt;' или '>', и разделены OR.
Я нашел, что это очень гибко, даже если это немного дорого.
set @i = 1;
INSERT INTO ARG_VALUE_LOOKUP(ARG_VALUE_LOOKUP_ID,ARGUMENT_NAME,VALUE,DESCRIPTION,UPDATE_TIMESTAMP,UPDATE_USER,VER_NBR,OBJ_ID)
select @i:= @i+1 as ARG_VALUE_LOOKUP_ID,ARGUMENT_NAME,VALUE,DESCRIPTION,CURRENT_TIMESTAMP,'admin',1,UUID()
FROM TEMP_ARG_VALUE_LOOKUP
order by ARGUMENT_NAME;
SELECT
col1, col2,
count(*) as intRow
FROM Table1
GROUP BY col1,col2
ORDER BY col3 desc
Невозможно воспроизвести функциональность брутабеля. Вы можете получить ожидаемые результаты, но скорее всего вы будете разочарованы на определенном этапе. Вот что говорит документация mysql:
Для других операторов, таких как SELECT, вы можете получить ожидаемые результаты, но это не гарантируется. В следующем утверждении вы можете подумать, что MySQL сначала оценит @a, а затем выполнит второе задание: SELECT @a, @a: = @ a + 1, ...; Однако порядок оценки выражений с использованием пользовательских переменных не определен.
blockquote>С уважением, Георги.