Case when Statement Not Working with my data - sql

While Working case statement i got stuck
For Eg i have below scenario
Amt StartDate EndDate Port Trade
10.00 9/21/2018 9/21/2020 NULL NULL
54,523.00 11/14/2018 11/15/2018 NULL NULL
756.00 11/14/2018 11/15/2018 NULL NULL
456.00 11/14/2018 11/15/2018 NULL NULL
86.00 11/14/2018 11/15/2018 NULL NULL
86.00 11/14/2018 11/15/2018 NULL NULL
453.00 11/14/2018 11/15/2018 NULL NULL
786.00 11/14/2018 11/15/2018 NULL NULL
86.00 11/14/2018 11/15/2018 NULL NULL
568.00 11/14/2018 11/15/2018 NULL NULL
12,358.00 11/14/2018 11/15/2018 NULL NULL
45,388.00 11/5/2018 12/5/2018 NULL NULL
75,368.00 8/9/2018 12/20/2018 call collateral
783,678.00 7/13/2018 1/14/2019 NULL NULL
1)what i am looking for is when startdate and enddate difference = 1
or Port like '%call%' and Trade='collateral' then amt
2) when startdate and enddate difference > 7
and Port not like '%call%' and Trade <> 'collateral' then amt
My First Condition Works
select CASE WHEN DATEDIFF(DAY,CAST(Startdate AS DATE),CAST(Enddate AS DATE))=1
OR (Port like 'Call' and [Trade]='collateral')
THEN amt ELSE 0 END AS money1
from tablename
But Second Condition not Working
select CASE WHEN (DATEDIFF(DAY,CAST(Startdate AS DATE),CAST(Enddate AS DATE))> 7 AND
DATEDIFF(DAY,CAST(Startdate AS DATE),CAST(Enddate AS DATE)) <= 9999)
and [Trade] <> 'collateral' and Portfolio not like '%Call%'
THEN amt ELSE 0 END AS money2 from tablename
excepted o/p
Amt StartDate EndDate money1 money2
10.00 9/21/2018 9/21/2020 10.00
54,523.00 11/14/2018 11/15/2018 54,523.00
756.00 11/14/2018 11/15/2018 756.00
456.00 11/14/2018 11/15/2018 456.00
86.00 11/14/2018 11/15/2018 86.00
86.00 11/14/2018 11/15/2018 86.00
453.00 11/14/2018 11/15/2018 453.00
786.00 11/14/2018 11/15/2018 786.00
86.00 11/14/2018 11/15/2018 86.00
568.00 11/14/2018 11/15/2018 568.00
12,358.00 11/14/2018 11/15/2018 12,358.00
45,388.00 11/5/2018 12/5/2018 45,388.00
75,368.00 8/9/2018 12/20/2018 75,368.00
783,678.00 7/13/2018 1/14/2019 783,678.00
Need Help i am using Sql server 2012.

Check whether PortFolio and Trade are NULL.
So:
SELECT CASE WHEN DATEDIFF(DAY,CAST(Startdate AS DATE),CAST(Enddate AS DATE))> 7 AND
DATEDIFF(DAY,CAST(Startdate AS DATE),CAST(Enddate AS DATE)) <= 9999 AND
([Trade] IS NULL OR [Trade] <> 'collateral') AND
(Portfolio IS NULL OR Portfolio NOT LIKE '%call%')
THEN amt ELSE 0 END AS money2
FROM tablename;

Your like operator should be '%Call%'
select CASE WHEN (DATEDIFF(DAY,CAST(Startdate AS DATE),CAST(Enddate AS DATE))> 7 AND
DATEDIFF(DAY,CAST(Startdate AS DATE),CAST(Enddate AS DATE)) <= 9999)
and [Trade] <> 'collateral' and Portfolio not like '%Call%'
THEN amt ELSE 0 END AS money2 from tablename

Related

SQL-SERVER Filter By ROW_NUMBER and Another Condition

I have this SQL-SERVER Query:
SELECT t.Id,
t.ClientTemplateFieldId,
t.ClientTemplateFieldOptionId,
t.TextData,
t.NumberData,
t.DateTimeData,
t.TreatmentDate,
t.rn FROM
(
SELECT tfd.Id,
tfd.ClientTemplateFieldId,
tfd.ClientTemplateFieldOptionId,
tfd.TextData,
tfd.NumberData,
tfd.DateTimeData,
t.TreatmentDate,
ROW_NUMBER() OVER (PARTITION BY tfd.ClientTemplateFieldId ORDER BY t.TreatmentDate DESC) as rn
FROM TemplateFieldData tfd
INNER JOIN
Treatment t ON tfd.TreatmentId = t.Id
WHERE tfd.IsDeleted = 0 AND
t.IsDeleted = 0 AND
tfd.ClientId = 2 AND
t.ClientId = 2 AND
t.PatientId = 6003720 AND
tfd.ClientTemplateFieldId IN
(1873,1874,1875,1876)
) AS t
--WHERE CLAUSE...
And this is the table result of the above query:
Id ClientTemplateFieldId ClientTemplateFieldOptionId TextData NumberData DateTimeData TreatmentDate rn
4324 1873 1627 NULL NULL NULL 2021-01-14 09:00:00.000 1
4325 1873 1628 NULL NULL NULL 2021-01-14 09:00:00.000 2
4326 1873 1631 NULL NULL NULL 2021-01-14 09:00:00.000 3
4322 1873 1627 NULL NULL NULL 2021-01-13 09:00:00.000 4
4323 1873 1629 NULL NULL NULL 2021-01-13 09:00:00.000 5
4320 1873 1626 NULL NULL NULL 2021-01-12 22:00:00.000 6
4321 1873 1630 NULL NULL NULL 2021-01-12 22:00:00.000 7
4338 1874 NULL SomeTxt NULL NULL 2021-01-14 09:00:00.000 1
4330 1874 NULL SomeTxt NULL NULL 2021-01-13 09:00:00.000 2
4327 1874 NULL SomeTxt NULL NULL 2021-01-12 22:00:00.000 3
4328 1875 NULL NULL 10.00 NULL 2021-01-12 22:00:00.000 1
4331 1876 1634 NULL NULL NULL 2021-01-13 09:00:00.000 1
4329 1876 1632 NULL NULL NULL 2021-01-12 22:00:00.000 2
What should I put in the Where Clause in order to retrieve all rows with row_number = 1 and
also if there is a row with the same TreatmentDate and ClientTemplateFieldId as of one of the rows where
row_number = 1, I need that row to.
Meaning I need this result:
Id ClientTemplateFieldId ClientTemplateFieldOptionId TextData NumberData DateTimeData TreatmentDate rn
4324 1873 1627 NULL NULL NULL 2021-01-14 09:00:00.000 1
4325 1873 1628 NULL NULL NULL 2021-01-14 09:00:00.000 2
4326 1873 1631 NULL NULL NULL 2021-01-14 09:00:00.000 3
4338 1874 NULL SomeTxt NULL NULL 2021-01-14 09:00:00.000 1
4328 1875 NULL NULL 10.00 NULL 2021-01-12 22:00:00.000 1
4331 1876 1634 NULL NULL NULL 2021-01-13 09:00:00.000 1
You could use MAX() window function instead of ROW_NUMBER() to get all the rows with the latest TreatmentDate for each ClientTemplateFieldId:
SELECT t.Id,
t.ClientTemplateFieldId,
t.ClientTemplateFieldOptionId,
t.TextData,
t.NumberData,
t.DateTimeData,
t.TreatmentDate,
t.rn
FROM (
SELECT tfd.Id,
tfd.ClientTemplateFieldId,
tfd.ClientTemplateFieldOptionId,
tfd.TextData,
tfd.NumberData,
tfd.DateTimeData,
t.TreatmentDate,
ROW_NUMBER() OVER (PARTITION BY tfd.ClientTemplateFieldId ORDER BY t.TreatmentDate DESC) AS rn,
MAX(t.TreatmentDate) OVER (PARTITION BY tfd.ClientTemplateFieldId) AS max_TreatmentDate
FROM TemplateFieldData tfd
INNER JOIN
Treatment t ON tfd.TreatmentId = t.Id
WHERE tfd.IsDeleted = 0 AND
t.IsDeleted = 0 AND
tfd.ClientId = 2 AND
t.ClientId = 2 AND
t.PatientId = 6003720 AND
tfd.ClientTemplateFieldId IN
(1873,1874,1875,1876)
) AS t
WHERE t.TreatmentDate = t.max_TreatmentDate
ROW_NUMBER() is not actually needed but I kept it in my query just in case you want it in the results.
If I assume that this entire query result (without the where condition) is created as a View called T for example, you can do the following:
SELECT *
FROM T
WHERE T.rn = 1
OR EXISTS
(SELECT 1 FROM T as T2
WHERE T2.TreatmentDate = T.TreatmentDate
AND T2.ClientTemplateFieldId = T.ClientTemplateFieldId
AND T.rn != 1
AND T2.rn = 1)

A problem with a simple join taking too long to finish

I´m having trouble identifying who to fix this simple join.
SELECT A.CUSER,
COUNT(*) AS QTD
FROM BO_PRODUCTCONFIG A WITH (NOLOCK)
INNER JOIN BO_PRICER001 B WITH (NOLOCK)
ON (
A.CIDBRANCH = B.CIDBRANCH
OR B.CIDBRANCH IS NULL
)
AND (
A.CIDPRODUCT = B.CIDPRODUCT
OR B.CIDPRODUCT IS NULL
)
My problem is, after adding the column B.CIDPRODUCT IS NULL this query takes hours to finish.
table BO_PRICER001 rows 286537
table BO_PRODUCTCONFIG rows 7934844
on the table BO_PRICER001 exists 15329 rows with null
with B.CIDPRODUCT IS NULL the live query show this plan:
and without this column the plan is:
I already try to force an index and switch to a subquery but the problem continues.
if possible, I really appreciate a help.
Sample of data from PRICER001
CIDPRICE CIDCOMPANY CIDBRANCH CIDTABLEPRICE CIDCOMMISSIONGROUP CIDPRODUCT CIDPERIODPAYMENT DENDDATEVALIDITY DSTARTDATEVALIDITY NINCREASEPERCENT LACTIVE DLASTUPDATE NINCREASEPERCENTORIG
XPTO0319 XPTO NULL NULL NULL NULL 319 9999-12-31 00:00:00.000 2018-08-27 00:00:00.000 2.100 1 2020-10-07 05:07:37.917 21.000
XPTO0321 XPTO NULL NULL NULL NULL 321 9999-12-31 00:00:00.000 2014-08-06 00:00:00.000 2.100 1 2020-10-07 05:07:37.917 21.000
XPTO0326 XPTO NULL NULL NULL NULL 326 9999-12-31 00:00:00.000 2018-08-27 00:00:00.000 3.150 1 2020-10-07 05:07:37.917 31.500
XPTO0328 XPTO NULL NULL NULL NULL 328 9999-12-31 00:00:00.000 2014-08-06 00:00:00.000 3.150 1 2020-10-07 05:07:37.917 31.500
XPTO0345 XPTO NULL NULL NULL NULL 345 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 4.530 1 2020-10-07 05:07:37.917 45.300
XPTO0390 XPTO NULL NULL NULL NULL 390 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 9.130 1 2020-10-07 05:07:37.917 91.300
XPTO0412 XPTO NULL NULL NULL NULL 412 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 11.500 1 2020-10-07 05:07:37.917 115.000
XPTO0428 XPTO NULL NULL NULL NULL 428 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 2.640 1 2020-10-07 05:07:37.917 26.400
XPTO0460 XPTO NULL NULL NULL NULL 460 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 5.690 1 2020-10-07 05:07:37.917 56.900
XPTO0515 XPTO NULL NULL NULL NULL 515 9999-12-31 00:00:00.000 2020-05-29 00:00:00.000 13.900 1 2020-10-07 05:07:37.917 139.000
Sample of data from PRODUCTCONFIG
CIDPRODUCTCONFIG CIDPRODUCT CIDPRODUCTMARKET CIDPRODUCTBUSINESS CIDPRODUCTLINE CIDPRODUCTGROUP CIDPRODUCTSUBGROUP CIDREGION CIDBRANCH CIDTEAM CIDTERRITORY LACTIVE LFLAG DLASTUPDATE CUSER CTPDCA
5840992036 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2036 1 NULL 2020-10-07 00:49:15.837 2036 1
5840992037 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2037 1 NULL 2020-10-07 00:49:15.837 2037 1
5840992038 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2038 1 NULL 2020-10-07 00:49:15.837 2038 1
5840992039 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2039 1 NULL 2020-10-07 00:49:15.837 2039 1
5840992040 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2040 1 NULL 2020-10-07 00:49:15.837 2040 1
5840992041 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2041 1 NULL 2020-10-07 00:49:15.837 2041 1
5840992042 584099 XPTO XPTO XPTO ACM FFK NULL 1402 NULL 2042 1 NULL 2020-10-07 00:18:20.783 2042 1
5840992044 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2044 1 NULL 2020-10-07 00:49:15.837 2044 1
5840992045 584099 XPTO XPTO XPTO ACM FFK NULL 1685 NULL 2045 1 NULL 2020-10-07 00:49:15.837 2045 1
5840992048 584099 XPTO XPTO XPTO ACM FFK NULL 1686 NULL 2048 1 NULL 2020-10-07 00:50:20.223 2048 1
OR kills performance. A typical workaround are multiple LEFT JOIN. Perhaps:
I´m having trouble identifying who to fix this simple join.
SELECT pc.CUSER,
COUNT(*) AS QTD
FROM BO_PRODUCTCONFIG pc LEFT JOIN
BO_PRICER001 prbp
ON pc.CIDBRANCH = prbp.CIDBRANCH AND
pc.CIDPRODUCT = prbp.CIDPRODUCT LEFT JOIN
BO_PRICER001 prb
ON pc.CIDBRANCH = prb.CIDBRANCH AND
prbp.CIDPRODUCT IS NULL LEFT JOIN
BO_PRICER001 prp
ON prp.CIDBRANCH IS NULL AND
prp.CIDPRODUCT = pc.CIDPRODUCT LEFT JOIN
BO_PRICER001 pr
ON prp.CIDBRANCH IS NULL AND
prp.CIDPRODUCT IS NULL
WHERE prbp.CIDBRANCH is not null OR prb.CIDBRANCH is not null OR pr.CIDPRODUCT is not null or pr.<some other column> is not null;

Join two table by dates and populate the missing data when one table has missing dates

In SQL Server, I have a two tables (tbl1 and tbl2) as shown below. tbl2 contains a list of all dates. In tbl1, some of the dates are missing.
tbl1
name nameid count date
-----------------------------------------------
apple 1 77 2019-07-29 00:00:00.000
orange 2 129 2019-07-29 00:00:00.000
apple 1 399 2019-08-05 00:00:00.000
orange 2 27 2019-08-05 00:00:00.000
apple 1 122 2019-08-12 00:00:00.000
orange 2 5 2019-08-19 00:00:00.000
tbl2
timeid date
5 2019-07-29 00:00:00.000
4 2019-08-05 00:00:00.000
3 2019-08-12 00:00:00.000
2 2019-08-19 00:00:00.000
1 2019-08-26 00:00:00.000
What I need is the table below. I need to join the two table, populate the name and nameid for the missing dates, and set those counts as 0.
date name nameid count timeid
---------------------------------------------------
2019-07-29 00:00:00.000 apple 1 77 5
2019-07-29 00:00:00.000 orange 2 129 5
2019-08-05 00:00:00.000 apple 1 399 4
2019-08-05 00:00:00.000 orange 2 27 4
2019-08-12 00:00:00.000 apple 1 122 3
2019-08-12 00:00:00.000 orange 2 0 3
2019-08-19 00:00:00.000 apple 1 0 2
2019-08-19 00:00:00.000 orange 2 5 2
2019-08-26 00:00:00.000 apple 1 0 1
2019-08-26 00:00:00.000 orange 2 0 1
I did the following:
SELECT t1.date, name, nameid, count, timeid
FROM tbl2 t1
LEFT JOIN tbl1 t2 ON t1.date = t2.date
and got this output:
date name nameid count timeid
----------------------------------------------------------
2019-07-29 00:00:00.000 apple 1 77 5
2019-07-29 00:00:00.000 orange 2 129 5
2019-08-05 00:00:00.000 apple 1 399 4
2019-08-05 00:00:00.000 orange 2 27 4
2019-08-12 00:00:00.000 apple 1 122 3
2019-08-19 00:00:00.000 orange 2 5 2
2019-08-26 00:00:00.000 NULL NULL NULL 1
It does not seem to be right. Does anyone know how I can generate the desired joined table?
Below is the code to generate tbl1 and tbl2
DROP TABLE IF EXISTS tbl1
CREATE TABLE tbl1
(
name VARCHAR (50) NOT NULL,
nameid INT NOT NULL,
count INT NOT NULL,
date DATETIME
);
INSERT INTO tbl1(name, nameid, count, date)
VALUES ('apple', 1, 77, '2019-07-29'),
('orange', 2, 129, '2019-07-29'),
('apple', 1, 399, '2019-08-05'),
('orange', 2, 27, '2019-08-05'),
('apple', 1, 122, '2019-08-12'),
('orange', 2, 5, '2019-08-19');
DROP TABLE IF EXISTS tbl2
CREATE TABLE tbl2
(
timeid INT NOT NULL,
date DATETIME
);
INSERT INTO tbl2(timeid, date)
VALUES (5,'2019-07-29'),
(4,'2019-08-05'),
(3,'2019-08-12'),
(2,'2019-08-19'),
(1,'2019-08-26');
To achieve your desired result, you need to cross join the distinct name values from tbl1 with the dates from tbl2 and then LEFT JOIN that to tbl1 again, using COALESCE to replace NULL values of count with 0:
SELECT t2.date, n.name, n.nameid, COALESCE(t1.count, 0) AS count, t2.timeid
FROM tbl2 t2
CROSS APPLY (SELECT DISTINCT name, nameid FROM tbl1) n
LEFT JOIN tbl1 t1 ON t1.date = t2.date AND t1.name = n.name
ORDER BY t2.date, n.name
Output:
date name nameid count timeid
2019-07-29 00:00:00.000 apple 1 77 5
2019-07-29 00:00:00.000 orange 2 129 5
2019-08-05 00:00:00.000 apple 1 399 4
2019-08-05 00:00:00.000 orange 2 27 4
2019-08-12 00:00:00.000 apple 1 122 3
2019-08-12 00:00:00.000 orange 2 0 3
2019-08-19 00:00:00.000 apple 1 0 2
2019-08-19 00:00:00.000 orange 2 5 2
2019-08-26 00:00:00.000 apple 1 0 1
2019-08-26 00:00:00.000 orange 2 0 1
Demo on dbfiddle

Get DATE when Price Changed

Im trying to perform some DATEDIFF calculations but i simply lack the knowledge to complete the task.
I got a table that keeps record of the articles sold with date when the operation took place and historic prices of the article. Since i live in a country with 30% of anual inflation. I must consider that factor to calculate the earning by every article sold.
It all works fine while i have the buying price saved and the date when a product price change took place. But, when that data was not saved as an approximation i would like to use the date when the operation with a different price took place.
As result of the following select operations:
USE Rusich
DECLARE
#IDNegocio AS INT,
#UsarIDProducto AS BIT,
#IDProducto AS VARCHAR(50),
#FechaInicio AS DATE,
#FechaFinal AS DATE,
#TamañoMinimoDeMuestra AS INT,
#SeVendeMinimoCadaXDias AS INT,
#Inflacion AS DECIMAL(18,3),
#AuxMargen AS DECIMAL(18,2),
#AuxDifDias AS INT;
SET #FechaInicio = '01/02/10';
SET #FechaFinal = '28/02/18';
SET #IDNegocio = 1;
SET #IDProducto = '6910101404918'; /*<<<< Cambiar a NULL segun necesidad*/
SET #TamañoMinimoDeMuestra = 1;
SET #SeVendeMinimoCadaXDias = 90;
SET #Inflacion = 0.083;
SELECT
AUXFechas.IDProducto,
AUXFechas.[$ Precio de Venta Historico],
AUXFechas.[Fecha Precio],
AUXFechas.[Fecha Venta],
AUXFechas.FechaAnterior,
AUXFechas.DiasDiferencia,
CAST(
CASE WHEN
AUXFechas.IDProducto NOT IN ('112', '113' , '114')
AND AUXFechas.[Fecha Precio] <= AUXFechas.[Fecha Venta]
AND StockDetalles.[Precio de Compra] <> 0
AND StockDetalles.[Precio de Compra] IS NOT NULL THEN
(1 - StockDetalles.[Precio de Compra] / AUXFechas.[$ Precio de Venta Historico]) * 100 - (AUXFechas.[$ Descuento]/100) - DATEDIFF(DAY, AUXFechas.[Fecha Precio], AUXFechas.[Fecha Venta]) * #Inflacion
ELSE
NULL
END
AS DECIMAL(18,2)) AS [% Margen Ganancia Real]
FROM
StockDetalles JOIN (
SELECT
Stock.ID AS IDProducto,
Stock.Cantidad AS #Disponible,
Recibos.Cantidad as [#Vendida],
Recibos.Precio AS [$ Precio de Venta Historico],
Recibos.Descuento AS [$ Descuento],
Stock.[Precio de Venta] AS [$ Precio],
Stock.[Fecha Actualizacion de Precio] AS [Fecha Precio],
CAST(RecibosRegistros.Fecha AS DATE) AS [Fecha Venta],
ISNULL(LAG(CAST(RecibosRegistros.Fecha AS DATE), 1) OVER (PARTITION BY Recibos.IDProducto ORDER BY RecibosRegistros.Fecha), Stock.[Fecha Actualizacion de Precio]) AS FechaAnterior,
/*Considera el caso cuando no existe un registro anterior y usa la fecha de actualizacion de precio si es posible*/
CASE WHEN (LAG(CAST(RecibosRegistros.Fecha AS DATE), 1) OVER (PARTITION BY Recibos.IDProducto ORDER BY RecibosRegistros.Fecha) IS NULL) AND CAST(RecibosRegistros.Fecha AS DATE) > Stock.[Fecha Actualizacion de Precio] THEN
(DATEDIFF(DAY, CAST(RecibosRegistros.Fecha AS DATE),
/*PARTITION BY PARTICIONA POR COLUMNA*/
ISNULL(LAG(CAST(RecibosRegistros.Fecha AS DATE), 1) OVER (PARTITION BY Recibos.IDProducto ORDER BY RecibosRegistros.Fecha), [Fecha Actualizacion de Precio])) / Recibos.Cantidad) * -1
ELSE
(DATEDIFF(DAY, CAST(RecibosRegistros.Fecha AS DATE),
/*PARTITION BY PARTICIONA POR COLUMNA*/
LAG(CAST(RecibosRegistros.Fecha AS DATE), 1) OVER (PARTITION BY Recibos.IDProducto ORDER BY RecibosRegistros.Fecha)) / Recibos.Cantidad) * -1
END AS DiasDiferencia
FROM
RecibosRegistros
JOIN Recibos ON RecibosRegistros.IDRecibo = Recibos.IDRecibo
JOIN Stock ON Recibos.IDProducto = Stock.ID
WHERE
RecibosRegistros.NegocioID = #IDNegocio
AND Stock.IDNegocio = #IDNegocio
AND Stock.ID != '111'
AND Stock.ID != '112'
AND Stock.ID != '113'
AND Stock.ID != '114'
AND Stock.ID = COALESCE(#IDProducto,Stock.ID)) AS AUXFechas ON StockDetalles.ID = AUXFechas.IDProducto
JOIN Categorias ON StockDetalles.CategoriaID = Categorias.ID
Im obtaining this result:
IDProducto $ Precio de Venta Historico Fecha Precio Fecha Venta FechaAnterior DiasDiferencia % Margen Ganancia Real
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6910101404918 15,00 2012-10-18 2012-07-23 2012-10-18 NULL NULL
6910101404918 15,00 2012-10-18 2012-09-01 2012-07-23 40 NULL
6910101404918 21,00 2012-10-18 2013-07-01 2012-09-01 303 NULL
6910101404918 21,00 2012-10-18 2013-09-02 2013-07-01 63 NULL
6910101404918 21,00 2012-10-18 2013-09-24 2013-09-02 22 NULL
0200002003867 28,00 2014-03-05 2014-07-08 2014-03-05 125 NULL
0200002003867 28,00 2014-03-05 2014-07-08 2014-07-08 0 NULL
0200002003867 28,00 2014-03-05 2014-10-23 2014-07-08 107 NULL
0200002003867 28,00 2014-03-05 2015-01-21 2014-10-23 90 NULL
0200002003867 28,00 2014-03-05 2015-04-06 2015-01-21 75 NULL
What i need to do is get a column with date (Fecha Precio) where [$ Precio de Venta Historico] changed.
Output should be:
IDProducto $ Precio de Venta Historico Fecha Precio Fecha Venta FechaAnterior DiasDiferencia % Margen Ganancia Real Fecha Cambio
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6910101404918 15,00 2012-10-18 2012-07-23 2012-10-18 NULL NULL NULL
6910101404918 15,00 2012-10-18 2012-09-01 2012-07-23 40 NULL 2012-10-18
6910101404918 21,00 2012-10-18 2013-07-01 2012-09-01 303 NULL NULL
6910101404918 21,00 2012-10-18 2013-09-02 2013-07-01 63 NULL 2012-09-01
6910101404918 21,00 2012-10-18 2013-09-24 2013-09-02 22 NULL 2012-09-01
0200002003867 28,00 2014-03-05 2014-07-08 2014-03-05 125 NULL NULL
0200002003867 28,00 2014-03-05 2014-07-08 2014-07-08 0 NULL 2014-07-08
0200002003867 28,00 2014-03-05 2014-10-23 2014-07-08 107 NULL 2014-07-08
0200002003867 28,00 2014-03-05 2015-01-21 2014-10-23 90 NULL 2014-07-08
0200002003867 28,00 2014-03-05 2015-04-06 2015-01-21 75 NULL 2014-07-08
My guess is that the solution must be related with LAG/LEAD and PartitionBY IDProducto but i dont know how to do it. Please Help
Added this code to try to get some result and i almost got it but not quite yet:
LAG(AUXFechas.[Fecha Venta], 1, NULL) OVER (PARTITION BY IDProducto, AUXFechas.[$ Precio de Venta Historico] ORDER BY AUXFechas.[Fecha Venta])
GOT:
6910101404918 Bandeja Plastica Borde Dorado Oval 23 Bazar 0 1 15,00 21,00 2012-10-18 2012-07-23 2012-10-18 NULL NULL NULL
6910101404918 Bandeja Plastica Borde Dorado Oval 23 Bazar 0 1 15,00 21,00 2012-10-18 2012-09-01 2012-07-23 40 NULL 2012-07-23
6910101404918 Bandeja Plastica Borde Dorado Oval 23 Bazar 0 1 21,00 21,00 2012-10-18 2013-07-01 2012-09-01 303 NULL NULL
6910101404918 Bandeja Plastica Borde Dorado Oval 23 Bazar 0 1 21,00 21,00 2012-10-18 2013-09-02 2013-07-01 63 NULL 2013-07-01
6910101404918 Bandeja Plastica Borde Dorado Oval 23 Bazar 0 1 21,00 21,00 2012-10-18 2013-09-24 2013-09-02 22 NULL 2013-09-02
That last date (2013-09-02) Should be the same as previous (2013-07-01)
Tryed with another product and got:
0200002003867 Bandeja Acero Oval 21cm Bazar 0 1 28,00 28,00 2014-03-05 2014-07-08 2014-03-05 125 NULL NULL
0200002003867 Bandeja Acero Oval 21cm Bazar 0 1 28,00 28,00 2014-03-05 2014-07-08 2014-07-08 0 NULL 2014-07-08
0200002003867 Bandeja Acero Oval 21cm Bazar 0 1 28,00 28,00 2014-03-05 2014-10-23 2014-07-08 107 NULL 2014-07-08
0200002003867 Bandeja Acero Oval 21cm Bazar 0 1 28,00 28,00 2014-03-05 2015-01-21 2014-10-23 90 NULL 2014-10-23
0200002003867 Bandeja Acero Oval 21cm Bazar 0 1 28,00 28,00 2014-03-05 2015-04-06 2015-01-21 75 NULL 2015-01-21
Only the first cell after NULL in the right column is OK but the rest sould be the same
Finally got what i wanted by using the FIRST_VALUE function:
FIRST_VALUE(AUXFechas.[Fecha Venta]) OVER (PARTITION BY AUXFechas.IDProducto, AUXFechas. [$ Precio de Venta Historico] ORDER BY AUXFechas.[Fecha Venta])
AND GOT THIS!:
IDProducto Fecha Precio Fecha Venta FechaAnterior DiasDiferencia (Sin nombre de columna)
7790002000483 2014-08-28 2012-04-14 2014-08-28 NULL 2012-04-14
7790002000483 2014-08-28 2012-05-03 2012-04-14 19 2012-04-14
7790002000483 2014-08-28 2012-05-03 2012-05-03 0 2012-04-14
7790002000483 2014-08-28 2012-06-02 2012-05-03 30 2012-04-14
7790002000483 2014-08-28 2012-06-02 2012-06-02 0 2012-04-14
7790002000483 2014-08-28 2012-06-02 2012-06-02 0 2012-04-14
7790002000483 2014-08-28 2012-06-18 2012-06-02 16 2012-04-14
7790002000483 2014-08-28 2012-07-05 2012-06-18 17 2012-04-14
7790002000483 2014-08-28 2012-07-14 2012-07-05 4 2012-04-14
7790002000483 2014-08-28 2012-07-20 2012-07-14 6 2012-04-14
7790002000483 2014-08-28 2012-07-23 2012-07-20 3 2012-04-14
7790002000483 2014-08-28 2012-07-23 2012-07-23 0 2012-04-14
7790002000483 2014-08-28 2013-01-30 2012-07-23 191 2013-01-30
7790002000483 2014-08-28 2013-07-20 2013-01-30 171 2013-01-30
7790002000483 2014-08-28 2013-10-16 2013-07-20 88 2013-01-30
7790002000483 2014-08-28 2015-07-14 2013-10-16 636 2015-07-14

SQL Date Range Query - Table Comparison

I have two SQL Server tables containing the following information:
Table t_venues:
venue_id is unique
venue_id | start_date | end_date
1 | 01/01/2014 | 02/01/2014
2 | 05/01/2014 | 05/01/2014
3 | 09/01/2014 | 15/01/2014
4 | 20/01/2014 | 30/01/2014
Table t_venueuser:
venue_id is not unique
venue_id | start_date | end_date
1 | 02/01/2014 | 02/01/2014
2 | 05/01/2014 | 05/01/2014
3 | 09/01/2014 | 10/01/2014
4 | 23/01/2014 | 25/01/2014
From these two tables I need to find the dates that haven't been selected for each range, so the output would look like this:
venue_id | start_date | end_date
1 | 01/01/2014 | 01/01/2014
3 | 11/01/2014 | 15/01/2014
4 | 20/01/2014 | 22/01/2014
4 | 26/01/2014 | 30/01/2014
I can compare the two tables and get the date ranges from t_venues to appear in my query using 'except' but I can't get the query to produce the non-selected dates. Any help would be appreciated.
Calendar Table!
Another perfect candidate for a calendar table. If you can't be bothered to search for one, here's one I made earlier.
Setup Data
DECLARE #t_venues table (
venue_id int
, start_date date
, end_date date
);
INSERT INTO #t_venues (venue_id, start_date, end_date)
VALUES (1, '2014-01-01', '2014-01-02')
, (2, '2014-01-05', '2014-01-05')
, (3, '2014-01-09', '2014-01-15')
, (4, '2014-01-20', '2014-01-30')
;
DECLARE #t_venueuser table (
venue_id int
, start_date date
, end_date date
);
INSERT INTO #t_venueuser (venue_id, start_date, end_date)
VALUES (1, '2014-01-02', '2014-01-02')
, (2, '2014-01-05', '2014-01-05')
, (3, '2014-01-09', '2014-01-10')
, (4, '2014-01-23', '2014-01-25')
;
The Query
SELECT t_venues.venue_id
, calendar.the_date
, CASE WHEN t_venueuser.venue_id IS NULL THEN 1 ELSE 0 END As is_available
FROM dbo.calendar /* see: http://gvee.co.uk/files/sql/dbo.numbers%20&%20dbo.calendar.sql for an example */
INNER
JOIN #t_venues As t_venues
ON t_venues.start_date <= calendar.the_date
AND t_venues.end_date >= calendar.the_date
LEFT
JOIN #t_venueuser As t_venueuser
ON t_venueuser.venue_id = t_venues.venue_id
AND t_venueuser.start_date <= calendar.the_date
AND t_venueuser.end_date >= calendar.the_date
ORDER
BY t_venues.venue_id
, calendar.the_date
;
The Result
venue_id the_date is_available
----------- ----------------------- ------------
1 2014-01-01 00:00:00.000 1
1 2014-01-02 00:00:00.000 0
2 2014-01-05 00:00:00.000 0
3 2014-01-09 00:00:00.000 0
3 2014-01-10 00:00:00.000 0
3 2014-01-11 00:00:00.000 1
3 2014-01-12 00:00:00.000 1
3 2014-01-13 00:00:00.000 1
3 2014-01-14 00:00:00.000 1
3 2014-01-15 00:00:00.000 1
4 2014-01-20 00:00:00.000 1
4 2014-01-21 00:00:00.000 1
4 2014-01-22 00:00:00.000 1
4 2014-01-23 00:00:00.000 0
4 2014-01-24 00:00:00.000 0
4 2014-01-25 00:00:00.000 0
4 2014-01-26 00:00:00.000 1
4 2014-01-27 00:00:00.000 1
4 2014-01-28 00:00:00.000 1
4 2014-01-29 00:00:00.000 1
4 2014-01-30 00:00:00.000 1
(21 row(s) affected)
The Explanation
Our calendar tables contains an entry for every date.
We join our t_venues (as an aside, if you have the choice, lose the t_ prefix!) to return every day between our start_date and end_date. Example output for venue_id=4 for just this join:
venue_id the_date
----------- -----------------------
4 2014-01-20 00:00:00.000
4 2014-01-21 00:00:00.000
4 2014-01-22 00:00:00.000
4 2014-01-23 00:00:00.000
4 2014-01-24 00:00:00.000
4 2014-01-25 00:00:00.000
4 2014-01-26 00:00:00.000
4 2014-01-27 00:00:00.000
4 2014-01-28 00:00:00.000
4 2014-01-29 00:00:00.000
4 2014-01-30 00:00:00.000
(11 row(s) affected)
Now we have one row per day, we [outer] join our t_venueuser table. We join this in much the same manner as before, but with one added twist: we need to join based on the venue_id too!
Running this for venue_id=4 gives this result:
venue_id the_date t_venueuser_venue_id
----------- ----------------------- --------------------
4 2014-01-20 00:00:00.000 NULL
4 2014-01-21 00:00:00.000 NULL
4 2014-01-22 00:00:00.000 NULL
4 2014-01-23 00:00:00.000 4
4 2014-01-24 00:00:00.000 4
4 2014-01-25 00:00:00.000 4
4 2014-01-26 00:00:00.000 NULL
4 2014-01-27 00:00:00.000 NULL
4 2014-01-28 00:00:00.000 NULL
4 2014-01-29 00:00:00.000 NULL
4 2014-01-30 00:00:00.000 NULL
(11 row(s) affected)
See how we have a NULL value for rows where there is no t_venueuser record. Genius, no? ;-)
So in my first query I gave you a quick CASE statement that shows availability (1=available, 0=not available). This is for illustration only, but could be useful to you.
You can then either wrap the query up and then apply an extra filter on this calculated column or simply add a where clause in: WHERE t_venueuser.venue_id IS NULL and that will do the same trick.
This is a complete hack, but it gives the results you require, I've only tested it on the data you provided so there may well be gotchas with larger sets.
In general what you are looking at solving here is a variation of gaps and islands problem ,this is (briefly) a sequence where some items are missing. The missing items are referred as gaps and the existing items are referred as islands. If you would like to understand this issue in general check a few of the articles:
Simple talk article
blogs.MSDN article
SO answers tagged gaps-and-islands
Code:
;with dates as
(
SELECT vdates.venue_id,
vdates.vdate
FROM ( SELECT DATEADD(d,sv.number,v.start_date) vdate
, v.venue_id
FROM t_venues v
INNER JOIN master..spt_values sv
ON sv.type='P'
AND sv.number BETWEEN 0 AND datediff(d, v.start_date, v.end_date)) vdates
LEFT JOIN t_venueuser vu
ON vdates.vdate >= vu.start_date
AND vdates.vdate <= vu.end_date
AND vdates.venue_id = vu.venue_id
WHERE ISNULL(vu.venue_id,-1) = -1
)
SELECT venue_id, ISNULL([1],[2]) StartDate, [2] EndDate
FROM (SELECT venue_id, rDate, ROW_NUMBER() OVER (PARTITION BY venue_id, DateType ORDER BY rDate) AS rType, DateType as dType
FROM( SELECT d1.venue_id
,d1.vdate AS rDate
,'1' AS DateType
FROM dates AS d1
LEFT JOIN dates AS d0
ON DATEADD(d,-1,d1.vdate) = d0.vdate
LEFT JOIN dates AS d2
ON DATEADD(d,1,d1.vdate) = d2.vdate
WHERE CASE ISNULL(d2.vdate, '01 Jan 1753') WHEN '01 Jan 1753' THEN '2' ELSE '1' END = 1
AND ISNULL(d0.vdate, '01 Jan 1753') = '01 Jan 1753'
UNION
SELECT d1.venue_id
,ISNULL(d2.vdate,d1.vdate)
,'2'
FROM dates AS d1
LEFT JOIN dates AS d2
ON DATEADD(d,1,d1.vdate) = d2.vdate
WHERE CASE ISNULL(d2.vdate, '01 Jan 1753') WHEN '01 Jan 1753' THEN '2' ELSE '1' END = 2
) res
) src
PIVOT (MIN (rDate)
FOR dType IN
( [1], [2] )
) AS pvt
Results:
venue_id StartDate EndDate
1 2014-01-01 2014-01-01
3 2014-01-11 2014-01-15
4 2014-01-20 2014-01-22
4 2014-01-26 2014-01-30