Search code examples
sqlsqlitesequences

How to compute the number of sequence on an sentence in SQLite?


I have one table which records the deliverings of some products to clients. Its basic scheme is very easy:

| DeliveryDate | IdClient | IdProduct | Quantity | Cost |

Well, one assumption is that the clients can only purchase one item at a time, and they begin purchasing Item1, eventually they could change and start buying Item2, stopping from buying Item1, and so on. That do not mean Item1, Item2, ..., ItemN is always the same product, they could vary.

So, what I want is being able to get the different items purchased for each costumer, with its initial date of purchase, and the number of sequence of each product for each client, since I could not guess in advance which item will be bought. With this scheme:

| IdClient | IdProduct | FirstTimeDate | NumSequence |

Let me explain with a sample:

Table:

| DeliveryDate | IdClient | IdProduct | Quantity | Cost |
| 2016-05-01 | 1234 | 9876 | 2 | 1000 |
| 2016-06-01 | 1234 | 9876 | 1 | 500 |
| 2016-07-01 | 1234 | 8765 | 2 | 2000 |
| 2016-08-01 | 1234 | 5432 | 3 | 3500 |
| 2016-06-01 | 3456 | 5432 | 2 | 1500 |
| 2016-07-01 | 3456 | 5432 | 1 | 700 |
| 2016-08-01 | 3456 | 9523 | 2 | 2500 |

Desired Output:

| IdClient | IdProduct | FirstTimeDate | NumSequence |
| 1234 | 9876 | 2016-05-01 | 1 |
| 1234 | 8765 | 2016-07-01 | 2 |
| 1234 | 5432 | 2016-08-01 | 3 |
| 3456 | 5432 | 2016-06-01 | 1 |
| 3456 | 9523 | 2016-08-01 | 2 |

I could manage to get everything, except the number of sequence, instead of that, with the sql sentence written below I can get the number of different products purchased for each client:

| IdClient | IdProduct | FirstTimeDate | NumOfDistinctProducts |
| 1234 | 9876 | 2016-05-01 | 3 |
| 1234 | 8765 | 2016-07-01 | 3 |
| 1234 | 5432 | 2016-08-01 | 3 |
| 3456 | 5432 | 2016-06-01 | 2 |
| 3456 | 9523 | 2016-08-01 | 2 |

And the sql (for simplicity, I run first one sql creating a temporary table, and after that I run the actual query):

// Query to create the temporary table:
CREATE TEMPORARY TABLE tmpNewDelivering AS WITH FT_CTE AS (
    SELECT min(Date) ChangeDate,* FROM Deliverings WHERE Deliverings.IdProduct IN ( // Actual IdProducts // )
    GROUP BY IdProduct, IdPatient
    ORDER BY Deliverings.Date ASC
)
SELECT * from FT_CTE;

// Query I want to improve:
SELECT case when C.StartDate = tND.ChangeDate then "Start" else "Change" end Type, C.NumProducts NumProducts, tND.*
FROM tmpNewDelivering tND INNER JOIN (
    SELECT IdClient, count(IdProduct) NumProducts, min(ChangeDate) StartDate
    FROM tmpNewDelivering 
    GROUP BY IdClient
    ) C ON tND.IdClient = C.IdClient
ORDER BY tCN.Fecha DESC

Solution

  • SQLite does not have some capabilities that would be useful for this.

    You an get the first three columns just using aggregation:

    select IdClient, IdProduct, min(DeliveryDate) as FirstTimeDate
    from IdClient
    group by IdPatient, IdProduct;
    

    To get the sequence, you can modify this to get the number of different products purchased on or before the current one:

    | NumOfDistinctProducts

    select IdClient, IdProduct, min(DeliveryDate) as FirstTimeDate,
           (select count(distinct d2.IdProduct)
            from Deliverings d2
            where d2.IdClient = d.IdClient and
                  d2.DeliveryDate <= d.DeliveryDate
           ) as NumSequence
    from Deliverings d
    group by IdPatient, IdProduct;
    

    Note: You can use a temporary table for this. If so, you can use the temporary table for the subquery. This is a good idea if you put an index on IdClient, DeliveryDate, IdProduct.