Select Active Lot

4

I am studying about queries in SQLServer and I have the following scenario:

I have a batch table that has the following fields:

Lot Table

Id INT  
ProdutoID INT  
Preco SMALLMONEY  
Inicio DATETIME  
Fim DATETIME

Product Table (Products)

Id INT  
Name VARCHAR  
Tipo INT  

Types table

Id INT  
Name VARCHAR  

NOTE: And a well-summarized example table

I need to make a query that gives me the current price of the product. Ex .:

Types

Id | Name
01 | Teste  
02 | Testando  

Products

Id | Name    | Tipo
01 | Celular | 01  
02 | Câmera  | 02

Lots

Id | ProdutoId | Preco | Inicio                  | Fim  
1  |         1 |    50 | 2017-08-14 13:10:57.980 | 2017-08-16 13:10:57.980
2  |         1 |   100 | 2017-08-12 13:10:57.980 | NULL

As you can see, Lots have 2 Registries the registration with NULL is the official price of the product and the first record is a promotion that starts on the 14th and ends on the 16th. the date of publication of this question is 15/08 the current price would be 50.

How do I query to select Product name, Product type, and current price? (Considering the promotion date)

NOTE: It should also work with these logs:

Id | ProdutoId | Preco | Inicio                  | Fim  
1  |         1 |    50 | 2017-08-14 13:10:57.980 | 2017-08-16 13:10:57.980
2  |         1 |   100 | 2017-08-12 13:10:57.980 | NULL
3  |         1 |   150 | 2017-08-17 13:10:57.980 | NULL

In this case, the value of that product will increase on the 17th.

Just to not be left blank, I'm doing the second query:

select p.Nome as 'Produto', t.Nome as 'Tipo', l.Preco, MAX(p.Inicio)
from Lote as l inner join Produtos as p on l.ProdutoId = p.Id
inner join Tipos as t on p.TipoId = t.Id
group by p.Nome, t.Nome, l.preco

But it does not work the right way obviously, thank you right away!

    
asked by anonymous 16.08.2017 / 00:15

3 answers

6

Here is a suggestion that uses the product table as a starting point.

-- código #1 v3
declare @Hoje datetime;
set @Hoje= cast(current_timestamp as date);

--
with ctePreços as (
SELECT P.Id, P.Name, T.Name as Tipo, 
       (SELECT top (1) Preco 
          from Lot as L1 
          where L1.ProdutoId = P.Id
                and L1.Fim is NULL
                and @Hoje >= L1.Inicio 
          order by L1.Inicio desc) as Oficial,
       (SELECT Preco 
          from Lot as L2 
          where L2.ProdutoId = P.Id
                and @Hoje between L2.Inicio and L2.Fim) as Oferta
  from Products as P
       inner join Types as T on T.Id = P.Tipo
)
SELECT Id, 
       Name as [Nome do produto], 
       Tipo as [Tipo de produto],
       coalesce(Oferta, Oficial) as [Preço atual]
  from ctePreços;

Here's another approach, which uses the batch table as a starting point. In this case, only the products that have information in the Lot table are listed.

-- código #2
declare @Hoje datetime;
set @Hoje= cast(current_timestamp as date);

--
with cteAtual as (
SELECT L.*,
       Seq= row_number() over (partition by L.ProdutoId order by L.Inicio desc)
  from Lot as L
  where L.Inicio <= @Hoje
        and (L.Fim is NULL or L.Fim >= @Hoje)
)
SELECT A.ProdutoId, 
       P.Name as [Nome do produto], 
       T.Name as [Tipo de produto],
       A.Preco as [Preço atual]
  from cteAtual as A
       inner join Products as P on P.Id = A.ProdutoId
       inner join Types as T on T.Id = P.Tipo
  where A.Seq = 1;         
    
16.08.2017 / 02:24
4

I believe the following query will solve your problem: I did not put the types because it is irrelevant to the problem, just be added, and just a question of names, I believe batch is not the correct name for this table. A lot must have an identification, date of manufacture and validity. This table looks more like a price list.

Select distinct
    p.nome,
    coalesce(lp.preco, l.preco,0) as preco
from produtos p 
left outer join lote lp on lp.produtoid = p.id 
                        and lp.id = (select 
                                        max(x.id) 
                                     from lote x 
                                     where x.produtoid = lp.produtoid 
                                     and x.inicio <= getdate() 
                                     and x.fim >= getdate())
left outer join lote l on l.produtoid = p.id 
                       and l.inicio <= getdate() 
                       and l.fim is null
    
16.08.2017 / 00:52
0

Use the expression WITH to prioritize prices together with the ROW_NUMBER function:

WITH Prices (Id,
             ProdutoID,
             Preco,
             Inicio,
             Fim,
             Prioridade)
AS (
  SELECT lot.Id,
         lot.ProdutoID,
         lot.Preco,
         lot.Inicio,
         lot.Fim,
         ROW_NUMBER() OVER(PARTITION BY lot.ProdutoID ORDER BY lot.Inicio) AS Prioridade
    FROM Lot lot
   WHERE GETDATE() BETWEEN lot.Inicio AND ISNULL(lot.Fim, GETDATE())
)
SELECT prod.Name  AS 'Nome do Produto',
       type.Name  AS 'Tipo do produto',
       pric.Preco AS 'Preço atual'
  FROM Products prod
       INNER JOIN Types type ON type.Id = prod.Tipo
       INNER JOIN Prices pric ON pric.ProdutoID = prod.Id
 WHERE pric.Prioridade = 1;
    
16.08.2017 / 14:32