SQL Copy value from relative child cells - sql

I have the following problem, I can't understand how to copy the values present in the line with level 0.1, in the cells of the relative father with level 0.
I would like to copy the values of Field1 and Field2
CREATE TABLE [dbo].[Demo](
[ID] [nvarchar](50) NOT NULL,
[PARENT_ID] [nvarchar](50) NOT NULL,
[FIELD1] [nvarchar](50) NOT NULL,
[FILED2] [nvarchar](50) NOT NULL,
[LVL] [nvarchar](50) NOT NULL
) ON [PRIMARY]
INSERT INTO [dbo].[Demo]
([ID]
,[PARENT_ID]
,[FIELD1]
,[FILED2]
,[LVL])
VALUES
(''
,'1234'
,'value01'
,'value02'
,'0.1')
INSERT INTO [dbo].[Demo]
([ID]
,[PARENT_ID]
,[FIELD1]
,[FILED2]
,[LVL])
VALUES
('1234'
,''
,''
,''
,'0')

I probably wouldn't copy them, but instead use the parent as a default in a query if the child value doesn't override. To make this easier, I would use NULLs rather than empty strings:
SELECT
p.[ID],
COALESCE(c.[FIELD1], p.[FIELD1]) as [FIELD1],
COALESCE(c.[FIELD2], p.[FIELD2]) as [FIELD2],
p.[LVL]
FROM
[Demo] p
INNER JOIN [Demo] c ON c.[PARENT_ID] = p.[ID]
COALESCE will, if the child field is null, use the parent field instead. If you are certain you want to keep enpty strings instead of nulls you can create an ANSI compatible query with CASE WHEN:
SELECT
p.[ID],
CASE WHEN c.[FIELD1] = '' THEN p.[FIELD1] ELSE c.[FIELD1] as [FIELD1],
CASE WHEN c.[FIELD2] = '' THEN p.[FIELD2] ELSE c.[FIELD2] as [FIELD2],
p.[LVL]
FROM
[Demo] p
INNER JOIN [Demo] c ON c.[PARENT_ID] = p.[ID]
But if you really want to copy them you can update a set of tables that are joined:
UPDATE c
SET
c.[FIELD1] = p.[FIELD1],
c.[FIELD2] = p.[FIELD2]
FROM
[Demo] p
INNER JOIN [Demo] c ON c.[PARENT_ID] = p.[ID]
Updating/copying creates a bit of a "have to keep doing it to keep them in sync" problem - realistically it's usually better to have the DB do the join as and when it's needed (it's very fast for a trivial operation like this)

Try this:
SELECT C.[ID]
,C.[PARENT_ID]
,ISNULL(NULLIF(P.[FIELD1], ''), C.[FIELD1]) AS [FIELD1]
,ISNULL(NULLIF(P.[FILED2], ''), C.[FILED2]) AS [FILED2]
,C.[LVL]
FROM [dbo].[Demo] C
LEFT JOIN [dbo].[Demo] P
ON C.[PARENT_ID] = P.[ID];

Related

How to dynamically create columns in SQL based on a list of ids

I am developing a stored procedure in SQL that receives a list of Ids (INT) from the backend. I need to dynamically create columns based on these and give the columns for each ID a name. Below is an example of how to do this with a fixed number of known Ids
SELECT DISTINCT
SE.SE_optionCode AS OptionCode,
LTRIM(RTRIM(DO.DO_Description)) AS Description,
LTRIM(RTRIM(CASE WHEN DG.DG_Description IS NULL THEN '' ELSE DG.DG_Description END)) AS GenericDescription,
LTRIM(RTRIM(CASE WHEN DG.DG_GenericCode IS NULL THEN 0 ELSE DG.DG_GenericCode END)) as GenericCode,
DCS.DC_CatCode AS Category,
LTRIM(RTRIM(DCS.DC_Description)) AS Category,
DCG.DC_CatCode AS GenericCategory,
LTRIM(RTRIM(DCG.DC_Description)) AS GenericCategory,
(SELECT DISTINCT 1 FROM NVDStandardEquipment WHERE SE_id = 93762 AND SE_optionCode = SE.SE_optionCode AND SE.SE_effectiveTo IS NULL) as Vehicle1,
(SELECT DISTINCT 1 FROM NVDStandardEquipment WHERE SE_id = 93786 AND SE_optionCode = SE.SE_optionCode AND SE.SE_effectiveTo IS NULL) as Vehicle2,
(SELECT DISTINCT 1 FROM NVDStandardEquipment WHERE SE_id = 93787 AND SE_optionCode = SE.SE_optionCode AND SE.SE_effectiveTo IS NULL) as Vehicle3,
(SELECT DISTINCT 1 FROM NVDStandardEquipment WHERE SE_id = 93801 AND SE_optionCode = SE.SE_optionCode AND SE.SE_effectiveTo IS NULL) as Vehicle4
FROM NVDStandardEquipment SE (NOLOCK)
INNER JOIN NVDDictionaryOption DO (NOLOCK) ON DO.DO_OptionCode = SE.SE_optionCode
INNER JOIN NVDDictionaryOptionGenericCatLink DOGCL (NOLOCK) ON DOGCL.OGCL_OptionCatCode = DO.DO_CatCode
LEFT JOIN NVDDictionaryOptionGenericLink DOGL ON DOGL.ogl_optioncode = SE.SE_optionCode
LEFT JOIN NVDDictionaryGeneric DG ON DG.DG_GenericCode = DOGL.OGL_genericCode
INNER JOIN NVDDictionaryCategory DCS (NOLOCK) ON DCS.DC_CatCode = DO.DO_CatCode
INNER JOIN NVDDictionaryCategory DCG (NOLOCK) ON DCG.DC_CatCode = DOGCL.OGCL_GenericCatCode
WHERE SE.SE_id in (93762,93786,93787,93801)
This will return a result set as in the attached image.
In my stored procedure I am declaring a temporary table where I store all the Ids received from the backend, somehow I would have to loop through these (Not sure if thats the best approach), I don't know whether is possible to generate the same output based on a ID list to generate the columns as per the example, has anyone done something similar or have some ideas about how I could achieve this?
Thanks in advance!
Let's say you need to update/maintain the following table.
CREATE TABLE [dbo].[Test1](
[MemberID] [varchar](50) NULL,
[InpatientDays] [varchar](50) NULL,
[ERVisits] [varchar](50) NULL,
[OfficeVisits] [varchar](50) NULL,
[Narcotics] [varchar](50) NULL,
[DaysSinceLastERVisit] [varchar](50) NULL,
[Pain] [varchar](50) NULL,
[TotalVisits] [varchar](50) NULL
) ON [PRIMARY]
GO
You have a file with a list of the following IDs.
AcuteDrugGapSmall
ClaimLines
MedicalClaims
PoorCare
ProviderCount
StartedOnCombination
Create a table to save the IDs.
CREATE TABLE [dbo].[Test2](
[ID] [varchar](50) NULL
) ON [PRIMARY]
GO
After you insert the IDs run the following to generate the TSQL script to add the new columns. I'm assuming they're all VARCHAR(50) in this example. You can tweak to code given more information regarding data_type and character_maximum_length. You can take a similar approach to drop columns if needed. If you had a flag in table Test2 indicating whether to add or drop the column.
DECLARE #SQL VARCHAR(MAX)
SELECT #SQL = STRING_AGG('ALTER TABLE [dbo].[Test1] ADD ' + ID + ' VARCHAR(50)', ' ')
FROM [dbo].[Test3]
EXECUTE (#SQL)
The above script generates and executes the following. Please mark as solution if this works for you.
ALTER TABLE [dbo].[Test1] ADD AcuteDrugGapSmallVARCHAR(50)
ALTER TABLE [dbo].[Test1] ADD ClaimLinesVARCHAR(50)
ALTER TABLE [dbo].[Test1] ADD MedicalClaimsVARCHAR(50)
ALTER TABLE [dbo].[Test1] ADD PoorCareVARCHAR(50)
ALTER TABLE [dbo].[Test1] ADD ProviderCountVARCHAR(50)
ALTER TABLE [dbo].[Test1] ADD StartedOnCombinationVARCHAR(50)

MS SQL: alter indexed view by including additional columns from new table

I need to update existing MS SQL indexed view by including additional columns values from newly created table.
Indexed view:
CREATE OR ALTER VIEW [dbo].[MySelectionInfo]
WITH schemabinding
AS
SELECT C.Id id0,
C.Code Code1,
C.Name Name2,
C.ProgramLevel Level3,
C.Department Department4,
C.City City10,
C.STATE State11,
C.StartDate StartDate12,
C.Deadline Deadline13,
B.ID Table_B_ID,
A.Id Table_A_ID
FROM dbo.Table_A A
INNER JOIN dbo.Table_B B ON A.id = B.Table_A_Id
INNER JOIN dbo.Table_C C ON C.Table_B_Id = B.Id
New table:
CREATE TABLE [dbo].[Table_D] (
[Id] [int] IDENTITY (1, 1) PRIMARY KEY NOT NULL,
[ModelName] [varchar](max) NOT NULL,
[Table_C_Id] [int] NOT NULL,
[AttributeValue] [varchar](max) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[UpdatedDate] [datetime] NOT NULL,
CONSTRAINT FK_Table_C_Id FOREIGN KEY (Table_C_Id) REFERENCES some_schema.dbo.[Table_C] (Id)
ON DELETE CASCADE
ON UPDATE CASCADE
)
Data in the new table:
I want to include only some of the ModelName column values as a column names and AttributeValue as values in the select * from [dbo].[MySelectionInfo] result set:
I can achieve the desired result using the PIVOT function:
CREATE OR ALTER VIEW [dbo].[MySelectionInfo]
WITH schemabinding
AS
SELECT C.Id id0,
C.Code Code1,
C.Name Name2,
C.StartDate StartDate12,
C.Deadline Deadline13,
B.ID Table_B_ID,
A.Id Table_A_ID
FROM dbo.Table_A A
INNER JOIN dbo.Table_B B ON A.id = B.Table_A_Id
INNER JOIN dbo.Table_C C ON C.Table_B_Id = B.Id
LEFT JOIN (SELECT PivotTable.Table_C_Id,
PivotTable.attribute1,
PivotTable.attribute2,
PivotTable.attribute3
FROM (SELECT Table_D.Table_C_Id,
Table_D.ModelName,
Table_D.AttributeValue
FROM dbo.Table_C
INNER JOIN dbo.Table_D
ON Table_C.Id = Table_D.Table_C_Id) AS sourceTable
PIVOT (
Max(AttributeValue) FOR ModelName IN (attribute1, attribute2, attribute3)
) AS PivotTable) dbo.Table_D D ON D.Table_C_Id = C.Id
But, after running the SQL statement above, I am not be able to create the clustered index for the view, because LEFT JOIN, PIVOT, MAX are prohibited to be used in the indexed views.
Question: Is there any other solutions to achieve the desired result and still have an existing view as an Indexed view?
if your data allow it, you could cross tab with case statements instead of PIVOTing:
/*
drop view dbo.mytestinfoview;
go
drop table dbo.Table1;
go
--*/
create table dbo.Table1
(
id int,
ModelName varchar(20),
AttributeValue int
);
insert into dbo.Table1(id, ModelName, AttributeValue)
select distinct o.object_id, concat('attribute', v.id), o.attributevalue
from
(
select
object_id ,
abs(checksum(newid())) % 2 as attributevalue
from sys.objects
) as o
cross apply (values(1), (2), (3), (4)) as v(id)
go
create or alter view dbo.mytestinfoview
with schemabinding
as
select id, count_big(*) as thecounter,
sum(isnull(case ModelName when 'attribute1' then AttributeValue end, 0)) as attribute1,
sum(isnull(case ModelName when 'attribute2' then AttributeValue else 0 end, 0)) as attribute2,
sum(isnull(case ModelName when 'attribute3' then AttributeValue else 0 end, 0)) as attribute3
from dbo.Table1
group by id
go
create unique clustered index idx_v1 on dbo.mytestinfoview(id);
go
select * from dbo.mytestinfoview;
go

SQL insert data dynamic column name from another table

i'm trying to insert data from one table to another with dynamic column name from #array to #array2
error
The multi-part identifier "s.id" could not be bound.
SQL CODE:
DECLARE #Array TABLE
(
id int not null,
dt varchar(12) not null,
ld varchar(16) not null,
val varchar(12) not null,
ty varchar(4) not null,
PRIMARY KEY CLUSTERED (id,dt)
)
DECLARE #Array2 TABLE
(
id int not null,
dt varchar(12) not null,
ld varchar(16) not null,
min varchar(12) null,
mout varchar(4) null,
PRIMARY KEY CLUSTERED (id,dt)
)
INSERT INTO #Array VALUES
('1','2015-11-11','2015-11-11','20:08','min')
,('2','2015-11-11','2015-11-11','20:08','mout')
,('3','2015-11-11','2015-11-11','20:08','min')
,('4','2015-11-11','2015-11-11','20:08','min')
Select * from #Array s
WHERE NOT EXISTS (select s.id,s.dt,s.ld,s.ty from #Array2
WHERE id != s.id AND dt != s.dt)
INSERT INTO #Array2 (id,dt,ld,s.ty) VALUES(s.id,s.dt,s.ld,s.val)
^
dynamic column name from #Array TABLE
here is SQL Fiddle link, thanks.
I would re-write your insert along the lines of:
INSERT INTO #Array2 (id,dt,ld,s.ty)
Select s.id,s.dt,s.ld,s.ty from #Array s
left join #Array2 a2 on a2.id = s.id
where a2.id is null
Your error is coming from the fact that Array2 doesn't have a ty column defined. The fix there is to either put it in there or re-evaluate what you are putting into it. Also, thumbs up for the fiddle link :)
EDIT:
On second reading of your question, do you want to dynamically add that column to array2? If so, then that would require quite a bit of mucking around, and I would try to find another solution. Changing your schema like that on the fly is ill-advised.
EDIT2:
INSERT INTO #Array2 (id,dt,ld,min,mout)
Select
s.id,
s.dt,
s.ld,
case s.ty when 'min' then s.val else '' end,
case s.ty when 'mout' then s.val else '' end
from #Array s
left join #Array2 a2 on a2.id = s.id
where a2.id is null
EDIT3
UPDATE a2
SET
a2.dt = s.dt,
a2.ld = s.ld,
a2.min = case s.ty when 'min' then s.val else '' end,
a2.mout = case s.ty when 'mout' then s.val else '' END
FROM #Array2 a2
LEFT JOIN #Array s ON a2.id = s.id
WHERE s.id IS NOT null

Multiple Table Insert with Merge?

I am trying to insert some rows in a parent/child relationship. How does one accomplish this in SQL?
This would be the base query I'd use to find the info I would be inserting:
SELECT * FROM parentTable p
INNER JOIN childTable c
ON p.ID = c.ParentTableID
WHERE p.PlanID = 123456
What needs to happen is that I insert the ParentTable row first which is really just a copy of the matched row but with a new PlanID and Created Date. Then I take that ParentTable ID from the inserted row and use that for the same process but for the Child Table.
So I need to do in .Net speak at least is where I loop through all parentTable matches and for each match create 1 childTable row.
I was trying to use MERGE and the OUTPUT clause but it seems like I'm maybe using a square peg for a round hole. Would I be better off using a CURSOR of some sorts?
So this is what I have so far based on the answer below. Unfortunately it isn't grabbing the SCOPE_IDENTITY()...is there a trick to it? Because that is returning NULL I get FK errors on the inserts.
USE MemberCenteredPlan
DECLARE #NewPlanID BIGINT;--49727690
DECLARE #OldPlanID BIGINT;--49725211
DECLARE #NewSWReAssID BIGINT;
SET #NewPlanID = 49727690
SET #OldPlanID = 49725211
BEGIN
INSERT INTO tblSocialWorkerReAssessment
SELECT
#NewPlanID
,[Discussed]
,Discussion
,NULL
,NULL
,NULL
,CreatedBy
,GETDATE()
,NULL
,NULL
FROM tblSocialWorkerReAssessment
WHERE PlanID = #OldPlanID
SELECT #NewSWReAssID = SCOPE_IDENTITY();
INSERT INTO tblPlanDomain
SELECT
#NewPlanID
,[DomainTypeID]
,[MemberOutcomes]
,[MemberPreferences]
,[DomainDate]
,[Steps]
,[ClinicalFunctionalConcerns]
,[ReportWageES]
,[ReportWageSSA]
,#NewSWReAssID
,[CreatedBy]
,GETDATE()
,NULL
,NULL
,NEWID()
FROM tblPlanDomain
WHERE planID = #OldPlanID
END
You don't need MERGE and you definitely don't need cursors. And an INSERT (or a MERGE) can only ever affect one table at a time, so you'll need to perform multiple statements anyway. If you are only ever dealing with one plan at a time, you can do this:
DECLARE #NewPlanID INT;
INSERT dbo.ParentTable(cols...)
SELECT cols...
FROM dbo.ParentTable WHERE PlanID = 123456;
SELECT #NewPlanID = SCOPE_IDENTITY();
INSERT dbo.ChildTable(ParentTableID, cols...)
SELECT #NewPlanID, cols...
FROM dbo.ChildTable WHERE PlanID = 123456;
If you need to reference multiple new plans, it gets a little more complicated, and in that case you would need to use MERGE (at the present time, INSERT's composable DML is a little on the light side - you can't reference the source table in the OUTPUT clause).
DECLARE #p TABLE(OldPlanID INT, NewPlanID INT);
MERGE dbo.ParentTable WITH (HOLDLOCK)
USING
(
SELECT ID, cols... FROM dbo.ParentTable
WHERE ID IN (123456, 234567)
) AS src ON src.ID IS NULL
WHEN NOT MATCHED THEN INSERT(cols...)
VALUES(src.cols...)
OUTPUT src.ID, inserted.ID INTO #p;
INSERT dbo.ChildTable(ParentTableID, cols...)
SELECT p.NewPlanID, t.cols...
FROM dbo.ChildTable AS t
INNER JOIN #p AS p
ON t.ParentTableID = p.OldPlanID;
However, you should be very wary about this... I link to several issues and unresolved bugs with MERGE in this answer over on dba.SE. I've also posted a cautionary tip here and several others agree.
I think this is what you're after.
Use Northwind
GO
SET NOCOUNT ON
IF OBJECT_ID('tempdb..#OrderAuditHolder') IS NOT NULL
begin
drop table #OrderAuditHolder
end
CREATE TABLE #OrderAuditHolder
(
[OriginalOrderID] [int] NOT NULL,
[NewOrderID] [int] NOT NULL,
[CustomerID] [nchar](5) NULL,
[EmployeeID] [int] NULL,
[OrderDate] [datetime] NULL,
[RequiredDate] [datetime] NULL,
[ShippedDate] [datetime] NULL,
[ShipVia] [int] NULL,
[Freight] [money] NULL,
[ShipName] [nvarchar](40) NULL,
[ShipAddress] [nvarchar](60) NULL,
[ShipCity] [nvarchar](15) NULL,
[ShipRegion] [nvarchar](15) NULL,
[ShipPostalCode] [nvarchar](10) NULL,
[ShipCountry] [nvarchar](15) NULL,
)
declare #ExampleOrderID int
select #ExampleOrderID = (select top 1 OrderID from dbo.Orders ords where exists (select null from dbo.[Order Details] innerOD where innerOD.OrderID = ords.OrderID ) )
print '/#ExampleOrderID/'
print #ExampleOrderID
print ''
insert into dbo.Orders (CustomerID,EmployeeID,OrderDate,RequiredDate,ShippedDate,ShipVia,Freight,ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry)
output #ExampleOrderID , inserted.OrderID,inserted.CustomerID,inserted.EmployeeID,inserted.OrderDate,inserted.RequiredDate,inserted.ShippedDate,inserted.ShipVia,inserted.Freight,inserted.ShipName,inserted.ShipAddress,inserted.ShipCity,inserted.ShipRegion,inserted.ShipPostalCode,inserted.ShipCountry
into #OrderAuditHolder
Select
CustomerID,EmployeeID,OrderDate,RequiredDate,ShippedDate,ShipVia,Freight,ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry
from dbo.Orders where OrderID = #ExampleOrderID
print '/#OrderAuditHolder/'
Select * from #OrderAuditHolder
print ''
Insert into dbo.[Order Details] ( OrderID , ProductID , UnitPrice , Quantity , Discount )
Select
holder.NewOrderID , od.ProductID , od.UnitPrice , od.Quantity , od.Discount
from #OrderAuditHolder holder
join dbo.[Order Details] od on holder.OriginalOrderID = od.OrderID
/* Note, the "join" is on the OriginalOrderID, but the inserted value is the NewOrderID */
/* below is not needed, but shows results */
declare #MaxOrderID int
select #MaxOrderID = (select MAX(OrderID) from dbo.Orders ords where exists (select null from dbo.[Order Details] innerOD where innerOD.OrderID = ords.OrderID ) )
select * from dbo.[Order Details] where OrderID = #MaxOrderID order by OrderID desc
/**/
IF OBJECT_ID('tempdb..#OrderAuditHolder') IS NOT NULL
begin
drop table #OrderAuditHolder
end
SET NOCOUNT OFF

Correlated join with outer fields as parameters

I need a way to join a table with a function's results. I'm not sure if it's possible and somehow I don't think it's a good idea. Let me try and explain the situation.
There is a table [Entities]:
[ID] [Description] [kWh] [kVArh] [kVAh] [OfferID] [CustomOfferID]
Another table [Data]:
[ID] [Timestamp] [Value]
And a function:
[Calc] (#offer, #customOffer, #kWh, #kVArh, #kVAh, #dtStart, #dtEnd)
So you can see there are entities, the entities' data (usage) and a function to calculate the cost.
I need to display the usage and cost of multiple entites:
[Description] [MWh] [MVA] [Cost]
[MWh] will be a SUM of all the entity's data over the period; [MVA] will be the MAX of all the data over the period; and [Cost] will SUM the [Cost] field from the sub query (function).
The query I figured would do the jobs looks like this:
SELECT [tc].[ID], [tc].[Desc]
, SUM([kWh].[Value]) / 1000 AS [MWh]
, MAX([kVAh].[Value]) / 1000 AS [MVA]
, SUM([cost].[Cost])
FROM [Tree_Cost] AS [tc]
INNER JOIN [Data] AS [kWh] ON [tc].[kWh] = [kWh].[ID]
INNER JOIN [Data] AS [kVAh] ON [tc].[kVAh] = [kVAh].[ID]
INNER JOIN
(
SELECT [tc].[ID], [Cost]
FROM [Calc] ([tc].[Offer_ID], [tc].[OfferCustom_ID], [tc].[kWh], [tc].[KVArh], [tc].[kVAh], #dtStart, #dtEnd)
) AS [cost] ON [tc].[ID] = [cost].[ID]
WHERE [tc].[Type] = 1 AND [tc].[TypeDesc] = 'GF_K_M'
AND [kWh].[Timestamp] BETWEEN #dtStart AND #dtEnd
AND [kVAh].[Timestamp] BETWEEN #dtStart AND #dtEnd
GROUP BY [tc].[ID], [tc].[Desc]
The real problem here is that I need to include the [ID] from the outer query in the result set of the inner query (function) in order to be able to join the two. Then I also need to be able to use the fields from the outer query as arguments for the inner query (function).
This is obviously not the way seeing as the [tc] identifier is not recognized in the inner query. So how am I supposed to accomplish something like this?
CREATE FUNCTION [dbo].[Calc]
( \#intOffer [int]
, \#intCustom [int]
, \#intP [int]
, \#intQ [int]
, \#intS [int]
, \#dtStart [datetime]
, \#dtEnd [datetime]
)
RETURNS TABLE
( [Entry] [nvarchar](200) NULL
, [Rate] [float] NULL
, [Unit] [nvarchar](50) NULL
, [Reading] [float] NULL
, [Cost] [float] NULL
, [DDate] [nvarchar](50) NULL
)
WITH EXECUTE AS CALLER
AS EXTERNAL NAME [OfferCalcLite].[UserDefinedFunctions].[SqlArray]
I'm not sure I understand correctly. Perhaps you can completely drop the JOIN:
INNER JOIN
(
SELECT [tc].[ID], [Cost]
FROM [Calc] ([tc].[Offer_ID], [tc].[OfferCustom_ID], [tc].[kWh], [tc].[KVArh], [tc].[kVAh], #dtStart, #dtEnd)
) AS [cost] ON [tc].[ID] = [cost].[ID]
and change:
, SUM([cost].[Cost])
into:
, SUM( [Calc] ( [tc].[Offer_ID]
, [tc].[OfferCustom_ID]
, [tc].[kWh]
, [tc].[KVArh]
, [tc].[kVAh]
, #dtStart, #dtEnd
)
) AS Cost