SQL counting based on date comparison - sql

I've got the following SQL query which gives me all of my assets which are older than two years, broken down by organization. Then I have to run it again and just remove the date comparison part in the WHERE clause to find out my total number of assets, so I can give a count of old, a count of total, and then a % old.
Is there a way to do this all as a single query? I'm thinking some type of case statement in the query maybe?
SELECT o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, COUNT(DISTINCT a.LabAssetSerialNbr) TotalAssets
FROM vw_DimLabAsset a
INNER JOIN vw_DimWorker w ON w.WorkerKey = a.LabAssetAssignedToWorkerKey
INNER JOIN vw_DimOrganizationHierarchy o ON o.OrganizationHierarchyUnitCd = w.WorkerOrganizationUnitCd
AND o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
WHERE a.SystemCreatedOnDtm < DATEADD(day, DATEDIFF(day, 0, DATEADD(yy, -2, GETDATE())), 0)
AND a.LabAssetTypeNm IN ('u_cmdb_ci_prototype_system', 'u_cmdb_ci_silicon')
AND a.LabAssetHardwareStatus <> 'retired'
AND (a.LabAssetHardwareSubStatus IS NULL OR a.LabAssetHardwareSubStatus <> 'archive')
GROUP BY o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm
ORDER BY 1, 2
I tried adding this to the select: `
SUM(CASE WHEN a.SystemCreatedOnDtm < DATEADD(day, DATEDIFF(day, 0, DATEADD(yy, -2, GETDATE())), 0) THEN 1 ELSE 0 END)
but that doesn't return the same count as the TotalAssets value.
Update
Here's the final query I ended up with:
DECLARE #date DateTime
SELECT #date = DATEADD(day, DATEDIFF(day, 0, DATEADD(yy, -2, GETDATE())), 0);
WITH pphw AS
(
SELECT DISTINCT o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr, MIN(a.SystemCreatedOnDtm) MinCreated
FROM vw_DimLabAsset a
INNER JOIN vw_DimWorker w ON a.LabAssetAssignedToWorkerKey = w.WorkerKey
INNER JOIN vw_DimOrganizationHierarchy o ON w.WorkerOrganizationUnitCd = o.OrganizationHierarchyUnitCd
AND o.OrganizationHierarchyUnitLevelThreeNm IS NOT NULL
AND o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
WHERE LabAssetHardwareStatus <> 'Retired'
AND (LabAssetHardwareSubStatus IS NULL OR LabAssetHardwareSubStatus <> 'Archive')
AND a.LabAssetTypeNm IN ('u_cmdb_ci_prototype_system', 'u_cmdb_ci_silicon')
GROUP BY o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr
)
SELECT OrganizationHierarchyUnitLevelThreeNm, OrganizationHierarchyUnitLevelFourNm,
SUM(CASE WHEN MinCreated < #date THEN 1 ELSE 0 END) AssetsOverTwoYears,
COUNT(DISTINCT LabAssetSerialNbr) TotalAssets
FROM pphw
GROUP BY OrganizationHierarchyUnitLevelThreeNm, OrganizationHierarchyUnitLevelFourNm
HAVING SUM(CASE WHEN MinCreated < #date THEN 1 ELSE 0 END) > 0
ORDER BY 1, 2

My answer is similar to tysonwright, but I think the GROUP BY clause should be outside of the sub-select. But, I would want sample data to validate this. The bottom line is that you should first gather all of the records that you want calculate metrics on via a sub-select. From there, you can perform your SUMs and COUNTs.
SELECT TMP1.OrganizationHierarchyUnitLevelThreeNm
,TMP1.OrganizationHierarchyUnitLevelFourNm
,TotalAssets = COUNT(TMP1.LabAssetSerialNbr)
,AssetsOver2YearsOld = SUM(TMP1.AssetOver2YearsOldInd)
,PercAssetsOver2YearsOld = SUM(TMP1.AssetOver2YearsOldInd) / COUNT(TMP1.LabAssetSerialNbr)
FROM (SELECT DISTINCT o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr
,AssetOver2YearsOldInd = CASE WHEN a.SystemCreatedOnDtm < DATEADD(d, DATEDIFF(d, 0, DATEADD(yy, -2, GETDATE())), 0) THEN 1 ELSE 0 END
FROM vw_DimLabAsset a
INNER JOIN vw_DimWorker w
ON w.WorkerKey = a.LabAssetAssignedToWorkerKey
INNER JOIN vw_DimOrganizationHierarchy o
ON o.OrganizationHierarchyUnitCd = w.WorkerOrganizationUnitCd
AND o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
WHERE a.LabAssetTypeNm IN ('u_cmdb_ci_prototype_system', 'u_cmdb_ci_silicon')
AND a.LabAssetHardwareStatus <> 'retired'
AND (a.LabAssetHardwareSubStatus IS NULL
OR a.LabAssetHardwareSubStatus <> 'archive')
) TMP1
GROUP BY TMP1.OrganizationHierarchyUnitLevelThreeNm, TMP1.OrganizationHierarchyUnitLevelFourNm
ORDER BY 1, 2
Update:
To remove the duplicates by date time, you can use either the MIN or MAX function, depending one what your requirement is:
SELECT TMP1.OrganizationHierarchyUnitLevelThreeNm
,TMP1.OrganizationHierarchyUnitLevelFourNm
,TotalAssets = COUNT(TMP1.LabAssetSerialNbr)
,AssetsOver2YearsOld = SUM(CASE WHEN TMP1.MaxSystemCreatedOnDtm < DATEADD(d, DATEDIFF(d, 0, DATEADD(yy, -2, GETDATE())), 0) THEN 1 ELSE 0 END)
,PercAssetsOver2YearsOld = SUM(CASE WHEN TMP1.MaxSystemCreatedOnDtm < DATEADD(d, DATEDIFF(d, 0, DATEADD(yy, -2, GETDATE())), 0) THEN 1 ELSE 0 END) / COUNT(TMP1.LabAssetSerialNbr)
FROM (SELECT DISTINCT o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr, MaxSystemCreatedOnDtm = MAX(a.SystemCreatedOnDtm)
FROM vw_DimLabAsset a
INNER JOIN vw_DimWorker w
ON w.WorkerKey = a.LabAssetAssignedToWorkerKey
INNER JOIN vw_DimOrganizationHierarchy o
ON o.OrganizationHierarchyUnitCd = w.WorkerOrganizationUnitCd
AND o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
WHERE a.LabAssetTypeNm IN ('u_cmdb_ci_prototype_system', 'u_cmdb_ci_silicon')
AND a.LabAssetHardwareStatus <> 'retired'
AND (a.LabAssetHardwareSubStatus IS NULL
OR a.LabAssetHardwareSubStatus <> 'archive')
GROUP BY o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr
) TMP1
GROUP BY TMP1.OrganizationHierarchyUnitLevelThreeNm, TMP1.OrganizationHierarchyUnitLevelFourNm
ORDER BY 1, 2

I think this will get you what you need:
SELECT
s.OrganizationHierarchyUnitLevelThreeNm,
s.OrganizationHierarchyUnitLevelFourNm,
COUNT(*) TotalAssets,
SUM(CASE WHEN s.SystemCreatedOnDtm < DATEADD(day, DATEDIFF(day, 0, DATEADD(yy, -2, GETDATE())), 0)
THEN 1 ELSE 0 END) AssetsOver2YearsOld,
SUM(CASE WHEN s.SystemCreatedOnDtm < DATEADD(day, DATEDIFF(day, 0, DATEADD(yy, -2, GETDATE())), 0)
THEN 1 ELSE 0 END) / COUNT(*) PercAssetsOver2YearsOld
FROM
(
SELECT
o.OrganizationHierarchyUnitLevelThreeNm,
o.OrganizationHierarchyUnitLevelFourNm
a.LabAssetSerialNbr,
a.SystemCreatedOnDtm
FROM
vw_DimLabAsset a
INNER JOIN
vw_DimWorker w
ON
w.WorkerKey = a.LabAssetAssignedToWorkerKey
INNER JOIN
vw_DimOrganizationHierarchy o
ON
o.OrganizationHierarchyUnitCd = w.WorkerOrganizationUnitCd
AND
o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
WHERE
a.LabAssetTypeNm IN ('u_cmdb_ci_prototype_system', 'u_cmdb_ci_silicon')
AND
a.LabAssetHardwareStatus <> 'retired'
AND
(a.LabAssetHardwareSubStatus IS NULL OR a.LabAssetHardwareSubStatus <> 'archive')
GROUP BY
o.OrganizationHierarchyUnitLevelThreeNm,
o.OrganizationHierarchyUnitLevelFourNm
a.LabAssetSerialNbr,
a.SystemCreatedOnDtm
) AS s

Related

How can I include more columns other than just percentage column in my sql query result?

When I use the below query I only get percentage column but I want the (buyer_id, buyer_name, created_date,total_work_orders_with_gtv_first_60_days, total_gtv_first_60_days, total_net_amount_first_60_days) to show as columns too. Would really appreciate your help please.
WITH results_cte AS (
SELECT
b.buyer_id,
b.buyer_name,
CAST(b.created_date AS DATE) AS created_date,
COALESCE(wo.total_work_orders_with_gtv_first_60_days, 0) AS total_work_orders_with_gtv_first_60_days,
COALESCE(wo.total_gtv_first_60_days, 0) AS total_gtv_first_60_days,
COALESCE(wo.total_net_amount_first_60_days, 0) AS total_net_amount_first_60_days
FROM dw.buyer b
LEFT JOIN (SELECT wo.buyer_id,
COUNT(CASE WHEN wo.gtv_date < DATEADD(DAY, 60, b.created_date) THEN wo.work_order_id ELSE NULL END) AS total_work_orders_with_gtv_first_60_days,
SUM(CASE WHEN wo.gtv_date < DATEADD(DAY, 60, b.created_date) THEN wo.gtv ELSE NULL END) AS total_gtv_first_60_days,
SUM(CASE WHEN wo.gtv_date < DATEADD(DAY, 60, b.created_date) THEN wo.net_amount ELSE NULL END) AS total_net_amount_first_60_days
FROM dw.work_order wo
JOIN dw.buyer b
ON wo.buyer_id = b.buyer_id
WHERE wo.gtv > 0
GROUP BY wo.buyer_id) wo
ON b.buyer_id = wo.buyer_id
WHERE b.buyer_segmentation = 'S - Self-Service'
AND b.status = 'Active'
AND b.created_date >= DATEADD(YEAR, -1, GETDATE())
)
SELECT (SELECT CAST(count(DISTINCT buyer_id) AS float) FROM results_cte WHERE total_work_orders_with_gtv_first_60_days > 0)
/ (SELECT CAST(count(DISTINCT buyer_id) AS float) FROM results_cte ) AS percentage

How to optimize this SQL Server query - Multiple subqueries

I have this query, with 4 subqueries, in SQL Server and I'm looking a way to optimize it:
DECLARE #INICIO DATE
DECLARE #FIN DATE
SET #INICIO='2020-06-17'
SET #FIN='2020-07-27'
SELECT VALO.FECHA_VALORACION,
VALO.CODIGO_PORTAFOLIO,
VALO.CUSIP,
VALO.NUMERO_INVERSION,
VALO.SM_GRUPO
SM_TIPO,
VALO.TIPO_INSTRUMENTO DESCRIPCION_INSTMT,
VALO.CODIGO_MONEDA CODIGO_MONEDA_PAGAR,
VALO.CODIGO_MONEDA CODIGO_MONEDA_RECIBIR,
VALO.ID_CONTRAPARTE,
OP.PRECIO
PRECIO_FX,
VALO.VALOR_NOMINAL,
VALO.VALOR_DERECHO,
VALO.VALOR_OBLIGACION,
VALO.VALOR_UTILIDAD_PERDIDA,
OP.FECHA FECHA_OPERACION,
VALO.TIPO_OPERACION,
OP.VALOR_OPERACION VALOR_OPERACION_COP,
OP.FECHA_VENCIMIENTO,
VALO.SM_GRUPO,
VALO.VALOR_UTILIDAD_PERDIDA_DER,
VALO.VALOR_UTILIDAD_PERDIDA_OBL,
(SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
FROM Spirit.TSPT_VALORACION_FUT NESTED
WHERE NESTED.CUSIP=VALO.CUSIP
AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
AND FECHA_VALORACION>=dateadd(month, datediff(month, 0, #INICIO), 0)
AND FECHA_VALORACION<=VALO.FECHA_VALORACION
AND VALOR_UTILIDAD_PERDIDA>0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS UTILIDAD_MENSUAL,
(SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
FROM Spirit.TSPT_VALORACION_FUT NESTED
WHERE NESTED.CUSIP=VALO.CUSIP
AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
AND FECHA_VALORACION>=dateadd(month, datediff(month, 0, #INICIO), 0)
AND FECHA_VALORACION<=VALO.FECHA_VALORACION
AND VALOR_UTILIDAD_PERDIDA<0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS PERDIDA_MENSUAL,
(SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
FROM Spirit.TSPT_VALORACION_FUT NESTED
WHERE NESTED.CUSIP=VALO.CUSIP
AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
AND NESTED.FECHA_VALORACION<=VALO.FECHA_VALORACION
AND NESTED.VALOR_UTILIDAD_PERDIDA>0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS UTILIDAD_ACUMULADA,
(SELECT SUM(NESTED.VALOR_UTILIDAD_PERDIDA)
FROM Spirit.TSPT_VALORACION_FUT NESTED
WHERE NESTED.CUSIP=VALO.CUSIP
AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
AND FECHA_VALORACION<=VALO.FECHA_VALORACION
AND VALOR_UTILIDAD_PERDIDA<0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS PERDIDA_ACUMULADA
FROM Spirit.TSPT_VALORACION_FUT VALO
INNER JOIN Spirit.TSPT_OPERACIONES OP ON OP.NUMERO_INVERSION = VALO.NUMERO_INVERSION
AND OP.TIPO_OPERACION = VALO.TIPO_OPERACION
AND OP.SM_GRUPO IN ('OPTION')
WHERE VALO.SM_GRUPO IN ('OPTION')
AND VALO.CODIGO_PORTAFOLIO IN ('AFP-P','AFP-F')
AND VALO.FECHA_VALORACION >= #INICIO
AND VALO.FECHA_VALORACION <= #FIN
ORDER BY VALO.CUSIP,VALO.FECHA_VALORACION
But I don't know how to integrate it and get the best. Thank you so much.
This is the result of a previous optimization process.
I've been trying some like this:
(SELECT sum (case when NESTED.VALOR_UTILIDAD_PERDIDA > 0 then NESTED.VALOR_UTILIDAD_PERDIDA else 0 end) as UTILIDAD_MENSUAL,
sum (case when NESTED.VALOR_UTILIDAD_PERDIDA < 0 then NESTED.VALOR_UTILIDAD_PERDIDA else 0 end) as PERDIDA_MENSUAL
FROM Spirit.TSPT_VALORACION_FUT NESTED
WHERE NESTED.CUSIP=VALO.CUSIP
AND NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
AND FECHA_VALORACION>=dateadd(month, datediff(month, 0, #INICIO), 0)
AND FECHA_VALORACION<=VALO.FECHA_VALORACION
AND VALOR_UTILIDAD_PERDIDA>0
GROUP BY CUSIP,CODIGO_PORTAFOLIO) AS ACUMULADOS
Since all your sub-queries seem to be coming from the same table, you can consolidate them into a single query in the FROM clause ... Try this ... I really can't debug the syntax without a table schema to reference ...
DECLARE #INICIO DATE
DECLARE #FIN DATE
SET #INICIO='2020-06-17'
SET #FIN='2020-07-27'
SELECT
VALO.FECHA_VALORACION,
VALO.CODIGO_PORTAFOLIO,
VALO.CUSIP,
VALO.NUMERO_INVERSION,
VALO.SM_GRUPO
SM_TIPO,
VALO.TIPO_INSTRUMENTO DESCRIPCION_INSTMT,
VALO.CODIGO_MONEDA CODIGO_MONEDA_PAGAR,
VALO.CODIGO_MONEDA CODIGO_MONEDA_RECIBIR,
VALO.ID_CONTRAPARTE,
OP.PRECIO
PRECIO_FX,
VALO.VALOR_NOMINAL,
VALO.VALOR_DERECHO,
VALO.VALOR_OBLIGACION,
VALO.VALOR_UTILIDAD_PERDIDA,
OP.FECHA FECHA_OPERACION,
VALO.TIPO_OPERACION,
OP.VALOR_OPERACION VALOR_OPERACION_COP,
OP.FECHA_VENCIMIENTO,
VALO.SM_GRUPO,
VALO.VALOR_UTILIDAD_PERDIDA_DER,
VALO.VALOR_UTILIDAD_PERDIDA_OBL,
S.UTILIDAD_MENSUAL,
S.PERDIDA_MENSUAL,
S.UTILIDAD_ACUMULADA,
S.PERDIDA_ACUMULADA
FROM
Spirit.TSPT_VALORACION_FUT VALO
INNER JOIN Spirit.TSPT_OPERACIONES OP ON
OP.NUMERO_INVERSION = VALO.NUMERO_INVERSION
AND OP.TIPO_OPERACION = VALO.TIPO_OPERACION
AND OP.SM_GRUPO IN ('OPTION')
OUTER APPLY (
SELECT
SUM(CASE WHEN FECHA_VALORACION>=dateadd(month, datediff(month, 0, #INICIO), 0) AND VALOR_UTILIDAD_PERDIDA>0
THEN NESTED.VALOR_UTILIDAD_PERDIDA
ELSE 0
END) UTILIDAD_MENSUAL,
SUM(CASE WHEN FECHA_VALORACION>=dateadd(month, datediff(month, 0, #INICIO), 0) AND VALOR_UTILIDAD_PERDIDA<0
THEN NESTED.VALOR_UTILIDAD_PERDIDA
ELSE 0
END) PERDIDA_MENSUAL,
SUM(CASE WHEN NESTED.VALOR_UTILIDAD_PERDIDA>0
THEN NESTED.VALOR_UTILIDAD_PERDIDA
ELSE 0
END) UTILIDAD_ACUMULADA,
SUM(CASE WHEN VALOR_UTILIDAD_PERDIDA<0
THEN NESTED.VALOR_UTILIDAD_PERDIDA
ELSE 0 END
) PERDIDA_ACUMULADA
FROM
Spirit.TSPT_VALORACION_FUT NESTED
WHERE
FECHA_VALORACION<=VALO.FECHA_VALORACION AND
NESTED.CUSIP = VALO.CUSIP AND
NESTED.CODIGO_PORTAFOLIO=VALO.CODIGO_PORTAFOLIO
GROUP BY
CUSIP,
CODIGO_PORTAFOLIO
) S
WHERE
VALO.SM_GRUPO IN ('OPTION')
AND VALO.CODIGO_PORTAFOLIO IN ('AFP-P','AFP-F')
AND VALO.FECHA_VALORACION >= #INICIO
AND VALO.FECHA_VALORACION <= #FIN
ORDER BY
VALO.CUSIP,
VALO.FECHA_VALORACION

SQL Server issue with select and group by with calculated columns

I have this SQL I am trying to build:
select
a.Name,
(SELECT COUNT(b.PlannedCollectionDate) WHERE b.PlannedCollectionDate < GETDATE()) AS Due,
(SELECT COUNT(b.PlannedCollectionDate) WHERE b.PlannedCollectionDate = GETDATE()) AS Today,
(SELECT COUNT(b.PlannedCollectionDate) WHERE b.PlannedCollectionDate = DATEADD(DAY, 1, GETDATE())) AS Expected,
(SELECT COUNT(b.PlannedCollectionDate) WHERE b.PlannedCollectionDate > DATEADD(DAY, 1, GETDATE())) AS Planned
from Centers AS a
INNER JOIN Collections AS b
ON a.Id = b.CenterId
GROUP BY a.Name
But I get an error:
Column 'Collections.PlannedCollectionDate' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I know I could do something like this:
select
a.Name,
(SELECT COUNT(Id) FROM Collections WHERE CenterId = a.Id AND PlannedCollectionDate < GETDATE()) AS Due,
(SELECT COUNT(Id) FROM Collections WHERE CenterId = a.Id AND PlannedCollectionDate = GETDATE()) AS Today,
(SELECT COUNT(Id) FROM Collections WHERE CenterId = a.Id AND PlannedCollectionDate = DATEADD(DAY, 1, GETDATE())) AS Expected,
(SELECT COUNT(Id) FROM Collections WHERE CenterId = a.Id AND PlannedCollectionDate > DATEADD(DAY, 1, GETDATE())) AS Planned
from Centers AS a
But I assume that is slower because I have to do multiple selects from the same table (Collections).
So, my question is, what can I do to make my first query work? I don't think grouping by PlannedCollectionDate is right, because it will mess up my count
I think you want conditional aggregation:
select ce.Name,
SUM(CASE WHEN co.PlannedCollectionDate < GETDATE() THEN 1 ELSE 0 END) AS Due,
SUM(CASE WHEN co.PlannedCollectionDate = GETDATE() THEN 1 ELSE 0 END) AS Today,
SUM(CASE WHEN co.PlannedCollectionDate = DATEADD(DAY, 1, GETDATE()) THEN 1 ELSE 0 END) AS Expected,
SUM(CASE WHEN co.PlannedCollectionDate > DATEADD(DAY, 1, GETDATE()) THEN 1 ELSE 0 END) AS Planned
from Centers ce join
Collections co
on ce.Id = co.CenterId
group by ce.Name;
This implements what you have written. Do note the use of meaningful table aliases.
However, it will not do what you want, because GETDATE() has a time component. To fix that, convert it to a date:
select ce.Name,
SUM(CASE WHEN co.PlannedCollectionDate < CONVERT(DATE, GETDATE()) THEN 1 ELSE 0 END) AS Due,
SUM(CASE WHEN co.PlannedCollectionDate = CONVERT(DATE, GETDATE()) THEN 1 ELSE 0 END) AS Today,
SUM(CASE WHEN co.PlannedCollectionDate = DATEADD(DAY, 1, CONVERT(DATE, GETDATE())) THEN 1 ELSE 0 END) AS Expected,
SUM(CASE WHEN co.PlannedCollectionDate > DATEADD(DAY, 1, CONVERT(DATE, GETDATE())) THEN 1 ELSE 0 END) AS Planned
from Centers ce join
Collections co
on ce.Id = co.CenterId
group by ce.Name;
Note that this assumes that PlannedCollectionDate does not have a time component.

SQL Split a column onto a different row

Hopefully I can explain this properly. I have this code which extracts the data onto excel. What I want to happen is to show detail for acquisition etc on one line and then show the same info again but showing the disposal amount as currently both values being shown on the same line isn't good for the user.
the code I have to get the data is this
DECLARE #DateNull DATE;
SET #DateNull = CAST('1900/01/01' AS DATE)
set transaction isolation level read uncommitted
select
a.DataAreaId,
a.AssetId AS AssetNumber,
a.Name as AssetName,
a.AssetGroup,
CASE WHEN b.Status = 0 then 'Not yet aquired'
WHEN b.Status = 1 then 'Open'
WHEN b.Status = 2 then 'Suspeneded'
WHEN b.Status = 3 then 'Closed'
WHEN b.Status = 4 then 'Sold'
WHEN b.Status = 5 then 'Scrapped'
WHEN b.Status = 6 then 'Transfered to low value pool' END as
AssetStatus,
NULLIF(b.AcquisitionDate,#DateNull) AS AcquisitionDate,
(b.ServiceLife) AS ServiceLife,
NULLIF(b.DisposalDate,#DateNull) AS DisposalDate,
AquisitionPrice.AmountMST*-1 As Aquisition,
--ISNULL(AquisitionPrice.AquisitionMonth,#DateNull) AS AquisitionMonth,
Depreciation.AmountMST*-1 As Depreciation,
NULLIF(Depreciation.DepreciationMonth,#DateNull) AS DepreciationMonth,
Disposal.AmountMST*-1 AS DisposalAmount,
--ISNULL(Disposal.DisposalMonth,#DateNull) AS DisposalMonth,
dv.OperatingDivision
from assettable a
Inner join AssetBook b
ON a.assetid=b.assetid
and a.dataareaid=b.dataareaid
LEFT JOIN
dbo.PSV_AX_KPIDefaultDimensionView DV
ON b.DefaultDimension = dv.DefaultDimension
LEFT JOIN
(select AssetID,BookId,DataAreaId,/*LowValuePoolType_AU,Reclassification*/
--DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0) AS AquisitionMonth,
TransType,SUM(AmountMST) AS AmountMST,SUm(RevaluationAmount) AS RevaluationAmount from AssetTrans
WHERE TransType =1 /*Aquisition*/Or TRANSTYPE =2 /*AcquisitionAdj*/
GROUP BY AssetID,BookId,DataAreaId,TransType
--DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0)
) AquisitionPrice
ON a.AssetId=AquisitionPrice.AssetId
AND a.DataAreaId=AquisitionPrice.DataAreaId
AND b.BookId=AquisitionPrice.BookId
LEFT JOIN
(select AssetID,BookId,DataAreaId,/*LowValuePoolType_AU,Reclassification*/
DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0) AS DepreciationMonth,
TransType,SUM(AmountMST) AS AmountMST,SUm(RevaluationAmount) AS RevaluationAmount from AssetTrans
WHERE TransType =3 /*Depreciation*/Or TRANSTYPE =4 /*DepreciationAdj*/
GROUP BY AssetID,BookId,DataAreaId,
DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0),
TransType
) Depreciation
ON a.AssetId=Depreciation.AssetId
AND a.DataAreaId=Depreciation.DataAreaId
AND b.BookId=Depreciation.BookId
Left join
(select AssetID,BookId,DataAreaId,TransType,
--DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0) AS DisposalMonth,
SUM(AmountMST) AS AmountMST,SUm(RevaluationAmount) AS RevaluationAmount from AssetTrans
WHERE TransType in (8,9) /*Disposal Sale,Disposal Scrap*/
GROUP BY AssetID,BookId,DataAreaId,TransType
--DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0)
) Disposal
ON a.AssetId=Disposal.AssetId
AND a.DataAreaId=Disposal.DataAreaId
AND b.BookId=Disposal.BookId
Whilst this whole scenario generally a bad idea, you can achieve this by UNIONing your Acquisition and Depreciation data together in your join, which will give you the two rows. Then you need to use a CASE statement to check which one to show.
You will need to handle the null values I have put into the ELSE part of the CASE in your excel sheet if you are not using Data Connected Tables.
I would also recommend cleaning up your code. Your formatting is rather inconsistent to say the least and you have a couple different spellings for 'Acquisition' in the same script...
Not having the data to try this on I do not know if it will work as is, but it should get you on your way:
DECLARE #DateNull DATE;
SET #DateNull = CAST('1900/01/01' AS DATE)
set transaction isolation level read uncommitted
select
a.DataAreaId,
a.AssetId AS AssetNumber,
a.Name as AssetName,
a.AssetGroup,
CASE WHEN b.Status = 0 then 'Not yet aquired'
WHEN b.Status = 1 then 'Open'
WHEN b.Status = 2 then 'Suspeneded'
WHEN b.Status = 3 then 'Closed'
WHEN b.Status = 4 then 'Sold'
WHEN b.Status = 5 then 'Scrapped'
WHEN b.Status = 6 then 'Transfered to low value pool' END as
AssetStatus,
case when APD.APDType = 'AcquisitionPrice' then NULLIF(b.AcquisitionDate,#DateNull) else null end AS AcquisitionDate,
case when APD.APDType = 'AcquisitionPrice' then (b.ServiceLife) else null end AS ServiceLife,
case when APD.APDType = 'AcquisitionPrice' then NULLIF(b.DisposalDate,#DateNull) else null end AS DisposalDate,
case when APD.APDType = 'AcquisitionPrice' then APD.AmountMST*-1 else null end As Aquisition,
--ISNULL(AquisitionPrice.AquisitionMonth,#DateNull) AS AquisitionMonth,
case when APD.APDType = 'Depreciation' then APD.AmountMST*-1 else null end As Depreciation,
case when APD.APDType = 'Depreciation' then NULLIF(APD.DepreciationMonth,#DateNull) else null end AS DepreciationMonth,
case when APD.APDType = 'Depreciation' then APD.AmountMST*-1 AS else null end DisposalAmount,
--ISNULL(Disposal.DisposalMonth,#DateNull) AS DisposalMonth,
dv.OperatingDivision
from assettable a
Inner join AssetBook b
ON a.assetid=b.assetid
and a.dataareaid=b.dataareaid
LEFT JOIN
dbo.PSV_AX_KPIDefaultDimensionView DV
ON b.DefaultDimension = dv.DefaultDimension
LEFT JOIN
(select 'AcquisitionPrice' as APDType, AssetID,BookId,DataAreaId,/*LowValuePoolType_AU,Reclassification*/
--DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0) AS AquisitionMonth,
TransType,SUM(AmountMST) AS AmountMST,SUm(RevaluationAmount) AS RevaluationAmount from AssetTrans
WHERE TransType =1 /*Aquisition*/Or TRANSTYPE =2 /*AcquisitionAdj*/
GROUP BY AssetID,BookId,DataAreaId,TransType
--DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0)
union all
select 'Depreciation' as APDType, AssetID,BookId,DataAreaId,/*LowValuePoolType_AU,Reclassification*/
DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0) AS DepreciationMonth,
TransType,SUM(AmountMST) AS AmountMST,SUm(RevaluationAmount) AS RevaluationAmount from AssetTrans
WHERE TransType =3 /*Depreciation*/Or TRANSTYPE =4 /*DepreciationAdj*/
GROUP BY AssetID,BookId,DataAreaId,
DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0),
TransType
) APDepreciation
ON a.AssetId=APD.AssetId
AND a.DataAreaId=APD.DataAreaId
AND b.BookId=APD.BookId
Left join
(select AssetID,BookId,DataAreaId,TransType,
--DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0) AS DisposalMonth,
SUM(AmountMST) AS AmountMST,SUm(RevaluationAmount) AS RevaluationAmount from AssetTrans
WHERE TransType in (8,9) /*Disposal Sale,Disposal Scrap*/
GROUP BY AssetID,BookId,DataAreaId,TransType
--DATEADD(month, DATEDIFF(month, 0, TRANSDATE), 0)
) Disposal
ON a.AssetId=Disposal.AssetId
AND a.DataAreaId=Disposal.DataAreaId
AND b.BookId=Disposal.BookId

How to improve the performance of this query that spans across multiple databases?

here is my query taking nearly 20 mins. pls suggest me changes to increase performance
SELECT DISTINCT
CONVERT(varchar(10),x.notice_date,120) Date,
Y.branch_name,
count(case when x.status='broken' and x.branch_name=y.branch_name then 1 end)
Broken,
count(case when x.type='Lote' and x.branch_name=y.branch_name then 1 end)
Lost,
( SELECT COUNT(A.car_no)
FROM DB2.dbo.z_mat A
WHERE DateAdd(Day, DateDiff(Day, 0,a.notice_date), 0)
= DateAdd(Day, DateDiff(Day, 0,x.notice_date), 0)
AND a.branch_name=y.branch_name
) mat,
( SELECT COUNT(B.car_no)
FROM DB2.dbo.z_cat B
WHERE DateAdd(Day, DateDiff(Day, 0,b.notice_date), 0)
= DateAdd(Day, DateDiff(Day, 0,x.notice_date), 0)
AND b.branch_name=y.branch_name
) cat,
( SELECT COUNT(C.car_no)
FROM DB2.dbo.z_pat C
WHERE DateAdd(Day, DateDiff(Day, 0,c.notice_date), 0)
= DateAdd(Day, DateDiff(Day, 0,x.notice_date), 0)
AND c.branch_name=y.branch_name
) pat
FROM DB1.dbo.Cars x
, DB2.dbo.Branch Y
WHERE DateAdd(Day, DateDiff(Day, 0,x.notice_date), 0)
> '2011-01-01'
GROUP BY CONVERT(varchar(10),x.notice_date,120)
, DateAdd(Day, DateDiff(Day, 0,x.notice_date), 0)
, y.branch_name
This might help. Give it a try.
SELECT
DISTINCT CONVERT(VARCHAR(10), car.notice_date, 120) AS NoticeDate
, brc.branch_name
, COUNT(CASE WHEN car.status = 'broken' AND car.branch_name = brc.branch_name THEN 1 END) Broken
, COUNT(CASE WHEN car.status = 'Lote' AND car.branch_name = brc.branch_name THEN 1 END) Lost
, mat.mat_count
, cat.cat_count
, pat.pat_count
FROM DB1.dbo.Cars car
, DB2.dbo.Branch brc
CROSS APPLY (
SELECT COUNT(mat.car_no) mat_count
FROM DB2.dbo.z_mat mat
WHERE DATEDIFF(d, mat.notice_date, car.notice_date) = 0
AND mat.branch_name = brc.branch_name
) mat
CROSS APPLY (
SELECT COUNT(cat.car_no) cat_count
FROM DB2.dbo.z_cat cat
WHERE DATEDIFF(d, cat.notice_date, car.notice_date) = 0
AND cat.branch_name = brc.branch_name
) cat
CROSS APPLY (
SELECT COUNT(pat.car_no) pat_count
FROM DB2.dbo.z_pat pat
WHERE DATEDIFF(d, pat.notice_date, car.notice_date) = 0
AND pat.branch_name = brc.branch_name
) pat
WHERE car.notice_date > '2011-01-01'
GROUP BY CONVERT(VARCHAR(10), car.notice_date, 120)
, brc.branch_name
SELECT CONVERT(varchar(10),x.notice_date,120) Date,Y.branch_name,
COUNT(case when x.status='broken' then 1 end) Broken,
COUNT(case when x.type='Lote' then 1 end) Lost,
SUM(mat) mat, SUM(cat) cat,SUM(pat) pat
FROM DB1.dbo.Cars x
JOIN DB2.dbo.Branch Y ON x.branch_name=y.branch_name
-- group by date and branch name for z_mat table
LEFT JOIN (select COUNT(car_no) mat,branch_name,DateAdd(Day, DateDiff(Day,notice_date), 0)) notice_date from DB2.dbo.z_mat GROUP BY branch_name,DateAdd(Day, DateDiff(Day,notice_date), 0)) AS a
ON a.branch_name = y.branch_name AND DateAdd(Day, DateDiff(Day, 0,x.notice_date), 0) = a.notice_date
-- group by date and branch name for z_cat table
LEFT JOIN (select COUNT(car_no) cat,branch_name,DateAdd(Day, DateDiff(Day,notice_date), 0)) notice_date from DB2.dbo.z_cat GROUP BY branch_name,DateAdd(Day, DateDiff(Day,notice_date), 0)) AS b
ON b.branch_name = y.branch_name AND DateAdd(Day, DateDiff(Day, 0,x.notice_date), 0) = b.notice_date
-- group by date and branch name for z_pat table
LEFT JOIN (select COUNT(car_no) pat,branch_name,DateAdd(Day, DateDiff(Day,notice_date), 0)) notice_date from DB2.dbo.z_pat GROUP BY branch_name,DateAdd(Day, DateDiff(Day,notice_date), 0)) AS c
ON c.branch_name = y.branch_name AND DateAdd(Day, DateDiff(Day, 0,x.notice_date), 0) = c.notice_date
WHERE DateAdd(Day, DateDiff(Day, 0,x.notice_date), 0)>'2011-01-01'
GROUP BY CONVERT(varchar(10),x.notice_date,120),DateAdd(Day, DateDiff(Day, 0,x.notice_date), 0),y.branch_name