Minha experiência com DBA não vai muito além do simples armazenamento e recuperação de dados no estilo CMS - portanto, essa pode ser uma pergunta boba, não sei!
Tenho um problema no qual preciso pesquisar ou calcular preços de férias para um determinado tamanho de grupo e um certo número de dias dentro de um determinado período de tempo. Por exemplo:
Quanto custa um quarto de hotel para 2 pessoas por 4 noites a qualquer momento em janeiro?
Tenho dados de preços e disponibilidade para, digamos, 5000 hotéis armazenados da seguinte forma:
Hotel ID | Date | Spaces | Price PP
-----------------------------------
123 | Jan1 | 5 | 100
123 | Jan2 | 7 | 100
123 | Jan3 | 5 | 100
123 | Jan4 | 3 | 100
123 | Jan5 | 5 | 100
123 | Jan6 | 7 | 110
456 | Jan1 | 5 | 120
456 | Jan2 | 1 | 120
456 | Jan3 | 4 | 130
456 | Jan4 | 3 | 110
456 | Jan5 | 5 | 100
456 | Jan6 | 7 | 90
Com esta tabela, eu posso fazer uma consulta assim:
SELECT hotel_id, sum(price_pp)
FROM hotel_data
WHERE
date >= Jan1 and date <= Jan4
and spaces >= 2
GROUP BY hotel_id
HAVING count(*) = 4;
resultados
hotel_id | sum
----------------
123 | 400
A HAVING
cláusula aqui garante que haja uma entrada para todos os dias entre minhas datas desejadas e que tenha os espaços disponíveis. ie O hotel 456 tinha 1 espaço disponível em Jan2, a cláusula HAVING retornaria 3, portanto não obtemos um resultado para o hotel 456.
Por enquanto, tudo bem.
No entanto, existe uma maneira de descobrir todos os períodos de 4 noites em janeiro em que há espaço disponível? Poderíamos repetir a consulta 27 vezes - incrementando as datas a cada vez, o que parece um pouco estranho. Ou outra maneira poderia ser armazenar todas as combinações possíveis em uma tabela de pesquisa como esta:
Hotel ID | total price pp | num_people | num_nights | start_date
----------------------------------------------------------------
123 | 400 | 2 | 4 | Jan1
123 | 400 | 2 | 4 | Jan2
123 | 400 | 2 | 4 | Jan3
123 | 400 | 3 | 4 | Jan1
123 | 400 | 3 | 4 | Jan2
123 | 400 | 3 | 4 | Jan3
E assim por diante. Teríamos que limitar o número máximo de noites e o número máximo de pessoas que procuraríamos - por exemplo, noites máximas = 28, pessoas máximas = 10 (limitado ao número de espaços disponíveis para esse período definido a partir dessa data).
Para um hotel, isso pode nos dar 28 * 10 * 365 = 102000 resultados por ano. 5000 hotéis = resultados de 500 milhões!
Mas teríamos uma consulta muito simples para encontrar a estadia mais barata de 4 noites em janeiro para 2 pessoas:
SELECT
hotel_id, start_date, price
from hotel_lookup
where num_people=2
and num_nights=4
and start_date >= Jan1
and start_date <= Jan27
order by price
limit 1;
Existe uma maneira de executar essa consulta na tabela inicial sem precisar gerar a tabela de pesquisa de 500m de linha !? por exemplo, gerar os 27 resultados possíveis em uma tabela temporária ou em alguma outra mágica de consulta interna?
No momento, todos os dados são mantidos em um banco de dados do Postgres - se necessário, para isso, podemos movê-los para algo mais adequado? Não tenho certeza se este tipo de consulta se encaixa nos padrões de mapa / redução para DBs no estilo NoSQL ...
fonte
Outra maneira, usando a
LAG()
função:Teste em: SQL-Fiddle
fonte
(spaces, day)
, talvez até um índice de cobertura(spaces, day, hotel_id, price)
.deve obter o resultado que você está procurando sem a necessidade de estruturas extras, embora, dependendo do tamanho dos dados de entrada, da sua estrutura de índice e da luminosidade do planejador de consultas, a consulta interna possa resultar em um spool para o disco. Você pode achar que é suficientemente eficiente. Advertência: meu conhecimento é sobre o MS SQL Server e os recursos de seu planejador de consultas,
portanto,a sintaxe acima pode precisar de duas vezes, apenas nos nomes das funções(o ypercube ajustou a sintaxe para que, provavelmente, seja compatível com o postgres agora, consulte o histórico de respostas da variante TSQL) .O exposto acima encontrará estadias que começam em janeiro, mas continuam em fevereiro. A adição de uma cláusula extra ao teste de data (ou o ajuste do valor final da data) lidará facilmente com isso, se não for desejável.
fonte
Independentemente do HotelID, você pode usar uma tabela de soma, com uma coluna calculada, da seguinte forma:
Não há chaves primárias ou estrangeiras nesta tabela, pois ela é usada apenas para calcular rapidamente várias combinações de valores. Se você precisar ou desejar mais de um valor calculado, crie uma nova visualização com um novo nome de visualização para cada valor do mês em combinação com cada um dos valores PP de pessoas e preços:
EXEMPLO DE CÓDIGO PSEUDO
SummedColumn = 2400
Por fim, junte-se à vista do HotelID. Para fazer isso, você precisará armazenar uma lista de todos os IDs do hotel em SummingTable (fiz na tabela acima), mesmo que o HotelID não seja usado para calcular na exibição. Igual a:
MAIS CÓDIGO PSEUDO
fonte