在动态加载的数据中缺少日期时在 ZingChart 中制作图表间隙?
Make chart gaps in ZingChart when missing dates in dynamically loaded data?
我一直在使用 ColdFusion 2016 和 ZingCharts(捆绑)使用 SQL 服务器动态创建图表,X 轴上有时间序列。当存在时间间隙时,我希望折线图也显示间隙,但该线是连续的并连续绘制每个数据点。
现在绘制的图表图片,您可以看到 10 月 29 日和 3 月日期之间没有 'gap',数据只是 运行 在一起:
我的数据通常以 15 分钟为增量,但在时间序列和数据中存在间隙的时间段(几天或几个月)。我联系了 ZingCharts,询问是否有某种样式标签可以控制日期是连续显示还是间隔显示,但没有。这是必须在数据级别进行操作的东西。如果我的数据是硬编码的,我将不得不添加空值,以便图表在时间序列中绘制有间隙,但我的图表是动态的(用户可以选择任意数量的 7 个参数添加到他们选择的日期范围的图表中).我找到了有关如何为硬编码数据解决此问题的信息,但我正在寻找动态加载 data/series 解决方案的想法。我还找到了有关 XML 文件 isInterpolated="false"
的已弃用 coldfusion 标签的信息,但这不再是一个选项。
我的问题是解决这个问题的最佳方法是什么? I found some information about creating a calendar table in SQL Server and unioning that with the table(s) providing the data so that all datetimes would be filled. 我想知道是否还有其他我没有想到的方法?感谢您的帮助,我对这一切都很陌生。
更新:这里是当前查询的数据,有点复杂。它根据选择的参数数量(7 个可用)和日期范围内的天数提取 "Nth" 行:
SELECT
distinct
datepart(year, t.sample_date) as [year]
,datepart(month, t.sample_date) as [month]
,datepart(day, t.sample_date) as [day]
,datepart(hour, t.sample_time) as [hr]
,datepart(minute, t.sample_time) as [min]
,convert(varchar(10), t.sample_date, 1) + ' ' +
RIGHT('0' + CONVERT([varchar](2), DATEPART(HOUR, t.sample_time)), 2) + ':' +
RIGHT('0' + CONVERT([varchar](2), DATEPART(MINUTE, t.sample_time)), 2) AS [datetime]
,t.stationdesc
<cfif isDefined("form.parameter") and ListFindNoCase(form.parameter, "salinity")>,ROUND(t.salinity,1) as salinity</cfif>
<!---plus 6 more parameters--->
FROM (
SELECT
[sample_date]
,sample_time
,stationdesc
<cfif isDefined("form.parameter") and ListFindNoCase(form.parameter, "salinity") >,salinity</cfif>
<!---plus 6 more parameters--->
, row_number() OVER (ORDER BY streamcode) AS rownum
FROM MyUnionizedTables
WHERE stationdesc = (<cfqueryparam value="#form.station#" cfsqltype="cf_sql_varchar">)
AND [sample_date] BETWEEN (<cfqueryparam value='#Form.StartDate#' cfsqltype="cf_sql_date">)
AND (<cfqueryparam value='#Form.EndDate#' cfsqltype="cf_sql_date">)
<cfif isDefined("form.parameter") and ListFindNoCase(form.parameter, "salinity")>and salinity > -25 and salinity <40 and salinity is not NULL </cfif>
<!---plus 6 more parameters--->
GROUP BY sample_date, sample_time, stationdesc, streamcode
<cfif isDefined("form.parameter") and ListFindNoCase(form.parameter, "salinity")>,salinity</cfif>
<!---plus 6 more parameters--->
) AS t
WHERE <!---returning Nth row when record sets (count of days between dates selected) are long--->
<cfif IsDefined("form.station") AND IsDefined("form.parameter") AND #ParamCount# LTE 3 AND form.station eq 'Coastal Bays - Public Landing' and #ctdays# gte 10> t.rownum % 64 = 0
<cfelseif IsDefined("form.parameter") AND #ParamCount# LTE 3 AND #ctDays# gte '5840'> t.rownum % 64 = 0
<!---plus lots more elseifs--->
<cfelseif IsDefined("form.parameter") AND #ParamCount# GTE 7 AND #ctDays# gte '350'> t.rownum % 8 = 0
<cfelse>t.rownum % 1 = 0</cfif>
ORDER BY
datepart(year, t.sample_date)
,datepart(month, t.sample_date)
,datepart(day, t.sample_date)
,datepart(hour, t.sample_time)
,datepart(minute, t.sample_time)
第二次更新(在 Leigh's link to query on GitHub 之后):
所以我实际上一直在处理与 Leigh 根据 "CTE Expression" 部分 here 发布的查询类似的查询。我转而尝试使用她的版本,如下所示。
我没有编写编辑,所以我正在使用现有的 table。 MyDataTable 有大约 2100 万行,有一个单独的 sample_date(datetime) 和 sample_time(datetime) [日期和时间是仪器的 PITA - b/c 以及这些数据的远程方式通过遥测,我们得到一个带有 'good date' 的日期时间列,但是一个我们称为 'sample_date' 的虚假时间值,然后是一个名为 'sample_time' 的单独日期时间列,其中包含一个虚假日期和一个 'good time'。 ] 有125个站点,每个站点的数据(例如,温度)来自不同的起点和终点dates/times,从2001年开始到现在。所以我需要为 125 个具有不同时间间隔的不同站点填补 date/time 间隔,这些间隔通常以 15 分钟为增量。
--- simulate main table(s)
--CREATE TABLE MyDataTable ( sample_date datetime, sample_time datetime, stationdesc nvarchar, wtemp float)
--- generate all dates within this range
DECLARE @startDate datetime
DECLARE @maxDate datetime
SET @startDate = '2015-01-01'
SET @maxDate = '2016-12-31'
--- get MISSING dates
;WITH missingDates AS
(
SELECT DATEADD(day,1,@startDate) AS TheDate
UNION ALL
SELECT DATEADD(day,1, TheDate)
FROM missingDates
WHERE TheDate < @maxDate
)
SELECT *
--[wtemp]
-- ,[stationdesc]
-- ,[TIMEVALUE]
FROM missingDates mi LEFT JOIN MyDataTable t ON t.sample_date = mi.TheDate
WHERE t.sample_date IS NULL
--and stationdesc = 'Back River - Lynch Point'
--ORDER BY timevalue
OPTION (MAXRECURSION 0)
当我按原样运行 这个查询时,我只得到 17 行数据。 TheDate 列列出日期为 12/15-12/31/16 的日期时间,所有时间均为 00:00:00.000。查询耗时49s.
与此同时,我和我的同事一直在研究替代方法。
--Putting data from only 1 station from our big datatable into the new testtable called '_testdatatable'
SELECT station, sample_date, sample_time, wtemp, streamcode, stationdesc, TIMEVALUE
INTO _testdatatable
FROM MyBigDataTable
WHERE (stationdesc = 'Back River')
order by [sample_date],[sample_time]
--Next, make a new table [_testdatatableGap] with all time values in 15min increments from a datetime table we made
SELECT [wtemp]=null
,[streamcode]='ABC1234'
,[stationdesc]= 'Back River'
,[TIMEVALUE]
into [tide].[dbo].[_testdatatableGap]
FROM DateTimeTable
WHERE (TIMEVALUE BETWEEN '4/19/2014' AND getdate())
--Then, get the missing dates from the Gap table and put into the testdatatable
INSERT into [_testdatatable]
( [wtemp]
,[streamcode]
,[stationdesc]
,[TIMEVALUE]
)
(SELECT
[wtemp]=null -- needs this for except to work
,
[streamcode]
,[stationdesc]
,
[TIMEVALUE]
FROM [_testdatatableGap]
EXCEPT
SELECT
[wtemp]=null -- needs this for except to work
,
[streamcode]
,[stationdesc]
,
[TIMEVALUE]
FROM [_testdatatable])
此方法创建了一个 table,所有 15 分钟的增量都在 date/time 中,从而生成了正确绘制的图表(下图)。但是,我们不知道如何在不制作多个 tables 的情况下将其扩展到完整的 125 个站的完整数据 table。
在采纳了一些建议并进行了大量研究、反复试验之后,我认为我已经解决了我的问题。我需要处理额外的复杂问题,有时需要减少返回和绘制的数据量,但这部分超出了我最初问题的范围。
我的简短回答是:
创建了一个 table MyBigDataTable 视图,其中包含一个附加列
名为“TIMEVALUE”的日期时间列。
制作了一个大的永久日期时间日历 table,其中的日期时间列名称相同:
“时间值”。
然后我开发了一组 SQL 查询
(a) 从 MyBigDataTable 收集数据并将其放入#temptable,并且
(b) 还从日历 table 中收集日期时间并将其放入相同的#temptable。
那么,
(c) 因为现在有时会有 2 个日期时间行,一个包含数据,另一个
对于空值,我 运行 一个查询,只保留包含数据的行(如果存在)
是 2 行匹配的日期时间和站点。然后可以将此数据绘制成图表。
- 这一切现在都动态写入我的 .cfm 页面、站点、日期
范围和参数由用户选择,现在是图表
在日期时间中成功绘制了正确的“间隙”
缺少数据。
这里是SQL(这里限制只有1个参数,我有8个):
--Step 1. Check if the temptable exists, if it does then delete it
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
BEGIN
DROP TABLE #TempTable
END
;
--Step 2. Create the temptable with data from the parameters, station and dates selected on the .cfm
SET NOCOUNT ON
SELECT
timevalue
,stationdesc
,wtemp
INTO #TempTable
FROM MyBigDataTable
WHERE
stationdesc = 'Station01'
and [timevalue] BETWEEN '5/29/2014' AND '10/01/2016'
GROUP BY
TIMEVALUE
,stationdesc
,wtemp
;
--Step 3. Now select datetimes from a big calendar table, and set stationdesc to the selected station,
--and rest of parameters to null. And do this for the same selected date range
INSERT INTO #TempTable
SELECT
[TIMEVALUE]
,[stationdesc]= 'Station01'
,wtemp=null
FROM MyDatetimeCalendarTable
WHERE [timevalue] BETWEEN '5/29/2014' AND '10/01/2016'
;
--Step 4. Run query on the temptable to gather data for chart, but b/c sometimes there will be 2 rows with the same datetime and station but one with data and one with nulls, this query only gathers the row with data if there are 2 rows with matching datetime and station
SELECT distinct *
FROM #TempTable a
WHERE
wtemp is not null or
wtemp is null and
not exists(
SELECT * FROM #TempTable b
WHERE a.timevalue=b.timevalue
and a.stationdesc=b.stationdesc and b.wtemp is not null)
ORDER BY timevalue
;
我需要对其进行全面测试并进行一些修改,但我认为这满足了答案的要求,因为到目前为止它正在做我需要它做的事情。感谢@Leigh 和@Dan Bracuk 的智慧(和耐心!)
我一直在使用 ColdFusion 2016 和 ZingCharts(捆绑)使用 SQL 服务器动态创建图表,X 轴上有时间序列。当存在时间间隙时,我希望折线图也显示间隙,但该线是连续的并连续绘制每个数据点。
现在绘制的图表图片,您可以看到 10 月 29 日和 3 月日期之间没有 'gap',数据只是 运行 在一起:
我的数据通常以 15 分钟为增量,但在时间序列和数据中存在间隙的时间段(几天或几个月)。我联系了 ZingCharts,询问是否有某种样式标签可以控制日期是连续显示还是间隔显示,但没有。这是必须在数据级别进行操作的东西。如果我的数据是硬编码的,我将不得不添加空值,以便图表在时间序列中绘制有间隙,但我的图表是动态的(用户可以选择任意数量的 7 个参数添加到他们选择的日期范围的图表中).我找到了有关如何为硬编码数据解决此问题的信息,但我正在寻找动态加载 data/series 解决方案的想法。我还找到了有关 XML 文件 isInterpolated="false"
的已弃用 coldfusion 标签的信息,但这不再是一个选项。
我的问题是解决这个问题的最佳方法是什么? I found some information about creating a calendar table in SQL Server and unioning that with the table(s) providing the data so that all datetimes would be filled. 我想知道是否还有其他我没有想到的方法?感谢您的帮助,我对这一切都很陌生。
更新:这里是当前查询的数据,有点复杂。它根据选择的参数数量(7 个可用)和日期范围内的天数提取 "Nth" 行:
SELECT
distinct
datepart(year, t.sample_date) as [year]
,datepart(month, t.sample_date) as [month]
,datepart(day, t.sample_date) as [day]
,datepart(hour, t.sample_time) as [hr]
,datepart(minute, t.sample_time) as [min]
,convert(varchar(10), t.sample_date, 1) + ' ' +
RIGHT('0' + CONVERT([varchar](2), DATEPART(HOUR, t.sample_time)), 2) + ':' +
RIGHT('0' + CONVERT([varchar](2), DATEPART(MINUTE, t.sample_time)), 2) AS [datetime]
,t.stationdesc
<cfif isDefined("form.parameter") and ListFindNoCase(form.parameter, "salinity")>,ROUND(t.salinity,1) as salinity</cfif>
<!---plus 6 more parameters--->
FROM (
SELECT
[sample_date]
,sample_time
,stationdesc
<cfif isDefined("form.parameter") and ListFindNoCase(form.parameter, "salinity") >,salinity</cfif>
<!---plus 6 more parameters--->
, row_number() OVER (ORDER BY streamcode) AS rownum
FROM MyUnionizedTables
WHERE stationdesc = (<cfqueryparam value="#form.station#" cfsqltype="cf_sql_varchar">)
AND [sample_date] BETWEEN (<cfqueryparam value='#Form.StartDate#' cfsqltype="cf_sql_date">)
AND (<cfqueryparam value='#Form.EndDate#' cfsqltype="cf_sql_date">)
<cfif isDefined("form.parameter") and ListFindNoCase(form.parameter, "salinity")>and salinity > -25 and salinity <40 and salinity is not NULL </cfif>
<!---plus 6 more parameters--->
GROUP BY sample_date, sample_time, stationdesc, streamcode
<cfif isDefined("form.parameter") and ListFindNoCase(form.parameter, "salinity")>,salinity</cfif>
<!---plus 6 more parameters--->
) AS t
WHERE <!---returning Nth row when record sets (count of days between dates selected) are long--->
<cfif IsDefined("form.station") AND IsDefined("form.parameter") AND #ParamCount# LTE 3 AND form.station eq 'Coastal Bays - Public Landing' and #ctdays# gte 10> t.rownum % 64 = 0
<cfelseif IsDefined("form.parameter") AND #ParamCount# LTE 3 AND #ctDays# gte '5840'> t.rownum % 64 = 0
<!---plus lots more elseifs--->
<cfelseif IsDefined("form.parameter") AND #ParamCount# GTE 7 AND #ctDays# gte '350'> t.rownum % 8 = 0
<cfelse>t.rownum % 1 = 0</cfif>
ORDER BY
datepart(year, t.sample_date)
,datepart(month, t.sample_date)
,datepart(day, t.sample_date)
,datepart(hour, t.sample_time)
,datepart(minute, t.sample_time)
第二次更新(在 Leigh's link to query on GitHub 之后):
所以我实际上一直在处理与 Leigh 根据 "CTE Expression" 部分 here 发布的查询类似的查询。我转而尝试使用她的版本,如下所示。 我没有编写编辑,所以我正在使用现有的 table。 MyDataTable 有大约 2100 万行,有一个单独的 sample_date(datetime) 和 sample_time(datetime) [日期和时间是仪器的 PITA - b/c 以及这些数据的远程方式通过遥测,我们得到一个带有 'good date' 的日期时间列,但是一个我们称为 'sample_date' 的虚假时间值,然后是一个名为 'sample_time' 的单独日期时间列,其中包含一个虚假日期和一个 'good time'。 ] 有125个站点,每个站点的数据(例如,温度)来自不同的起点和终点dates/times,从2001年开始到现在。所以我需要为 125 个具有不同时间间隔的不同站点填补 date/time 间隔,这些间隔通常以 15 分钟为增量。
--- simulate main table(s)
--CREATE TABLE MyDataTable ( sample_date datetime, sample_time datetime, stationdesc nvarchar, wtemp float)
--- generate all dates within this range
DECLARE @startDate datetime
DECLARE @maxDate datetime
SET @startDate = '2015-01-01'
SET @maxDate = '2016-12-31'
--- get MISSING dates
;WITH missingDates AS
(
SELECT DATEADD(day,1,@startDate) AS TheDate
UNION ALL
SELECT DATEADD(day,1, TheDate)
FROM missingDates
WHERE TheDate < @maxDate
)
SELECT *
--[wtemp]
-- ,[stationdesc]
-- ,[TIMEVALUE]
FROM missingDates mi LEFT JOIN MyDataTable t ON t.sample_date = mi.TheDate
WHERE t.sample_date IS NULL
--and stationdesc = 'Back River - Lynch Point'
--ORDER BY timevalue
OPTION (MAXRECURSION 0)
当我按原样运行 这个查询时,我只得到 17 行数据。 TheDate 列列出日期为 12/15-12/31/16 的日期时间,所有时间均为 00:00:00.000。查询耗时49s.
与此同时,我和我的同事一直在研究替代方法。
--Putting data from only 1 station from our big datatable into the new testtable called '_testdatatable'
SELECT station, sample_date, sample_time, wtemp, streamcode, stationdesc, TIMEVALUE
INTO _testdatatable
FROM MyBigDataTable
WHERE (stationdesc = 'Back River')
order by [sample_date],[sample_time]
--Next, make a new table [_testdatatableGap] with all time values in 15min increments from a datetime table we made
SELECT [wtemp]=null
,[streamcode]='ABC1234'
,[stationdesc]= 'Back River'
,[TIMEVALUE]
into [tide].[dbo].[_testdatatableGap]
FROM DateTimeTable
WHERE (TIMEVALUE BETWEEN '4/19/2014' AND getdate())
--Then, get the missing dates from the Gap table and put into the testdatatable
INSERT into [_testdatatable]
( [wtemp]
,[streamcode]
,[stationdesc]
,[TIMEVALUE]
)
(SELECT
[wtemp]=null -- needs this for except to work
,
[streamcode]
,[stationdesc]
,
[TIMEVALUE]
FROM [_testdatatableGap]
EXCEPT
SELECT
[wtemp]=null -- needs this for except to work
,
[streamcode]
,[stationdesc]
,
[TIMEVALUE]
FROM [_testdatatable])
此方法创建了一个 table,所有 15 分钟的增量都在 date/time 中,从而生成了正确绘制的图表(下图)。但是,我们不知道如何在不制作多个 tables 的情况下将其扩展到完整的 125 个站的完整数据 table。
在采纳了一些建议并进行了大量研究、反复试验之后,我认为我已经解决了我的问题。我需要处理额外的复杂问题,有时需要减少返回和绘制的数据量,但这部分超出了我最初问题的范围。
我的简短回答是:
创建了一个 table MyBigDataTable 视图,其中包含一个附加列 名为“TIMEVALUE”的日期时间列。
制作了一个大的永久日期时间日历 table,其中的日期时间列名称相同: “时间值”。
然后我开发了一组 SQL 查询
(a) 从 MyBigDataTable 收集数据并将其放入#temptable,并且
(b) 还从日历 table 中收集日期时间并将其放入相同的#temptable。
那么, (c) 因为现在有时会有 2 个日期时间行,一个包含数据,另一个 对于空值,我 运行 一个查询,只保留包含数据的行(如果存在) 是 2 行匹配的日期时间和站点。然后可以将此数据绘制成图表。
- 这一切现在都动态写入我的 .cfm 页面、站点、日期 范围和参数由用户选择,现在是图表 在日期时间中成功绘制了正确的“间隙” 缺少数据。
这里是SQL(这里限制只有1个参数,我有8个):
--Step 1. Check if the temptable exists, if it does then delete it
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
BEGIN
DROP TABLE #TempTable
END
;
--Step 2. Create the temptable with data from the parameters, station and dates selected on the .cfm
SET NOCOUNT ON
SELECT
timevalue
,stationdesc
,wtemp
INTO #TempTable
FROM MyBigDataTable
WHERE
stationdesc = 'Station01'
and [timevalue] BETWEEN '5/29/2014' AND '10/01/2016'
GROUP BY
TIMEVALUE
,stationdesc
,wtemp
;
--Step 3. Now select datetimes from a big calendar table, and set stationdesc to the selected station,
--and rest of parameters to null. And do this for the same selected date range
INSERT INTO #TempTable
SELECT
[TIMEVALUE]
,[stationdesc]= 'Station01'
,wtemp=null
FROM MyDatetimeCalendarTable
WHERE [timevalue] BETWEEN '5/29/2014' AND '10/01/2016'
;
--Step 4. Run query on the temptable to gather data for chart, but b/c sometimes there will be 2 rows with the same datetime and station but one with data and one with nulls, this query only gathers the row with data if there are 2 rows with matching datetime and station
SELECT distinct *
FROM #TempTable a
WHERE
wtemp is not null or
wtemp is null and
not exists(
SELECT * FROM #TempTable b
WHERE a.timevalue=b.timevalue
and a.stationdesc=b.stationdesc and b.wtemp is not null)
ORDER BY timevalue
;
我需要对其进行全面测试并进行一些修改,但我认为这满足了答案的要求,因为到目前为止它正在做我需要它做的事情。感谢@Leigh 和@Dan Bracuk 的智慧(和耐心!)