Pergunta

Estou implementando uma pequena fila de punho que processo começa a correr pela primeira vez. Eu estou usando uma tabela em um banco de dados para fazer isso. Aqui está a estrutura da tabela (estou zombando-lo em SQLite):

        "id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL ,
        "identifier" VARCHAR NOT NULL ,
        "priority_number" INTEGER DEFAULT 15,
        "timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP,
        "description" VARCHAR

Eu estou tentando escrever SQL para me dar a linha de que processo pode ser executado em seguida. Aqui está alguns dados de exemplo:

id  identifier  priority_number timestamp   description
1   test1   15  2009-01-20 17:14:49 NULL
2   test2   15  2009-01-20 17:14:56 NULL
3   test3   10  2009-01-20 17:15:03 NULL
4   test4   15  2009-01-20 17:15:08 NULL
5   test5   15  2009-01-20 17:32:23 NULL
6   test6   14  2009-01-20 17:32:30 NULL
7   test7   7   2009-01-20 17:32:38 NULL
8   test8   20  2009-01-20 17:32:57 NULL
9   test9   7   2009-01-21 13:47:30 NULL
10  test10  15  2009-01-21 13:50:52 NULL

Se eu usar este SQL, eu posso obter os dados na ordem correta:

select * from queue_manager order by priority_number, timestamp;

Isso vai me dar o item com o número de prioridade mais baixa (mais importante), na parte superior, e nesses números de prioridade, o mais antigo na fila (por timestamp) no topo.

Eu poderia executar essa consulta, e só tomar a primeira linha, mas eu preferiria fazer isso com uma consulta SQL que me daria a uma linha do processo que está no topo da fila (no exemplo dados acima , a linha com id = 7).

Eu tentei fazer auto junções e subconsultas, mas devo estar tendo um bloqueio mental -. Eu simplesmente não consigo fazer direito

Agradecemos antecipadamente!

Editar

Eu esqueci de mencionar que eu estou olhando para uma consulta independente de banco de dados. Eu estou zombando isso no SQLite, mas há uma boa possibilidade de que irá implementar isso no DB2 ou Oracle. Eu tinha pensado em usar um "limite 1" operador tipo na minha consulta, mas isso é diferente entre diferentes bancos de dados.

Foi útil?

Solução

Veja se isso funciona:

select * from queue_manager where priority_number = 
(select min(priority_number) from queue_manager) and  
timestamp = (select min(timestamp) 
from queue_manager qm2 
where qm2.priority_number = queue_manager.priority_number)

Outras dicas

select * from queue_manager order by priority_number, timestamp LIMIT 1;

Como para tal chamada "independência de banco de dados", que é um mito para a maioria das tarefas do mundo real. Como regra geral, você não pode mesmo criar o esquema de forma independente do banco de dados.

Se você quer que seja 'seguro concorrente' em algo como InnoDB fazer:

1) Adicionar um campo 'IN_PROGRESS'.

2) Desligue AutoCommit

3) SELECT * FROM queue_manager onde IN_PROGRESS = 0 ordem por priority_number, timestamp LIMITE PARA UDPATE 1;

4) ACTUALIZAÇÃO queue_manager SET IN_PROGRESS = 1 onde ID = X;

5) COMMIT

6) fazer o trabalho. Em seguida, exclua a linha quando o seu feito à satisfação. Tenha um 'processo principal' alavanca / redelegate / limpeza antigos empregos 'IN_PROGRESS'.

A melhor maneira de fazer isso é banco de dados dependentes; é uma coisa muito mais simples ter diferentes procs de recuperação para o destino diferente SGBDs contra todos a sobrecarga de cursores ou outras construções.

Selecionar um número limitado de linhas é feito de forma diferente em diferentes sabores de SQL, então dependendo do que você está usando pode haver um construído em forma de fazê-lo. Por exemplo, em MS SQL Server:

SELECT TOP 1
     identifier,
     priority_number,
     timestamp,
     description
FROM
     dbo.Queue_Manager
ORDER BY
     priority_number,
     timestamp

Para fazer isso no SQL ANSI compatível, os seguintes métodos deve funcionar:

    SELECT
         QM1.identifier,
         QM1.priority_number,
         QM1.timestamp,
         QM1.description
    FROM
         Queue_Manager QM1
    LEFT OUTER JOIN Queue_Manager QM2 ON
         QM2.priority_number < QM1.priority_number OR
         (QM2.priority_number = QM1.priority_number AND QM2.timestamp < QM1.timestamp)
    /* If you're concerned that there might be an exact match by priority_number
and timestamp then you might want to add a bit more to the join */
    WHERE
         QM2.identifier IS NULL

Ou você pode tentar:

SELECT
     QM1.identifier,
     QM1.priority_number,
     QM1.timestamp,
     QM1.description
FROM
     Queue_Manager QM1
INNER JOIN
     (
          SELECT
               priority_number
               MIN(timestamp) AS timestamp,
          FROM
               Queue_Manager
          WHERE
               priority_number = 
                    (
                         SELECT
                              MIN(priority_number)
                         FROM
                              Queue_Manager
                    )
          GROUP BY
               priority_number
     ) SQ1 ON
          SQ1.priority_number = QM1.priority_number AND
          SQ1.timestamp = QM1.timestamp

Nem contas de método para correspondências exatas em ambos os priority_number e timestamp, então se você acha que isso é possível (e talvez até mesmo se você não), você vai precisar adicionar uma linha ou duas para ir mais um nível usando o identificador ou outra coisa que garante a exclusividade. Ou simplesmente escrever seu front-end para lidar com o caso ocasional de ficar para trás duas linhas (talvez simplesmente ignorar o segundo - você vai obtê-lo na próxima vez through)

.

Test cada método e ver o que funciona melhor para você.

Além disso, o quão grande você espera na fila para obter? Poderia ser razoável apenas consulta com seu ORDER BY e só tem a extremidade dianteira recuperar a primeira linha.

Leia nesta seção e selecione a variante que lhe proporciona a mais compatibilidade adequada. Provavelmente o uso de cursores é a única forma mais ou menos universalmente compatível, mas tem alguma penalidade de desempenho que pode não fazer valer a pena (perfil!).

Bancos de dados relacionais não são grandes em filas de gestão.

Tente olhar para MSMQ no mundo Windows, ActiveMQ no mundo java ou Websphere MQ no mundo dos negócios.

Estes produtos fazem uma única coisa, gerenciar filas, mas eles fazê-lo bem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top