如何在 SQL 上使用 PIVOT 以及列数检查和分组等附加条件?
How to use PIVOT on SQL with additional criteria like colum count check and grouping?
下面 SQL 查询的当前输出是:
Time | SumValue(CE+PE)
2 列 - 确保输出的数量正好是十。
如何将其转置为:
Time | CE1Value | CE2Value |... |CE5Value | PE1Value | ... PE5Value
11 列。
确保同一特定时间的十条记录全部存在,否则跳到下一分钟(下一条记录)。
我假设它是按时间排序的,默认情况下我可以使用 order by - 它是最佳的吗?
针对 MS Access 中的数据使用 windows 中的独立 vbs 文件。
mySQL = "SELECT [Data.Time],"& Quantity &"*Sum([Data.Price]) AS SumOfPrice FROM Data WHERE ( ( [Data.Ticker] Like '"& CE1 &"' Or [Data.Ticker] Like '"& CE2 &"' Or [Data.Ticker] Like '"& CE3 &"' Or [Data.Ticker] Like '"& CE4 &"' Or [Data.Ticker] Like '"& CE5 &"' Or [Data.Ticker] Like '"& PE1 &"' Or [Data.Ticker] Like '"& PE2 &"' Or [Data.Ticker] Like '"& PE3 &"' Or [Data.Ticker] Like '"& PE4 &"' Or [Data.Ticker] Like '"& PE5 &"' ) AND ([Data.DateTr]=#"& DateIn &"#)) GROUP BY [Data.Time] HAVING [Data.Time] > #"& startTime(i) &"# and (((Count([Data.Ticker]))=10))"
例如。为了理解 :
数据table是:
DateTr|Ticker|Time|Price
22July2016|Apple|3:20 AM|15
22July2016|Apple|3:21 AM|16
22July2016|Apple|3:23 AM|14
22July2016|Amazon|3:20 AM|16
22July2016|Amazon|3:21 AM|14
22July2016|Amazon|3:22 AM|14
22July2016|Amazon|3:23 AM|14
例如。 Apple 数据用于 3:22 ,因此请跳过并转到下一个。
但同时要确保——在我的例子中,计数是 2(在本例中是 Apple+Amazon)10。 CE1 = 苹果,PE1 = 亚马逊
早期输出:
3:20|31
3:21|30
3:23|28
需要新输出:
3:20|15|16
3:21|16|14
so on.
代码与CE1、CE2、PE2等匹配
谢谢
如果数据驻留在 MS Access 中,请考虑 crosstab query,您可以使用 PIVOT
子句显式指定 10 列:
TRANSFORM SUM(t.Price) As SumPrice
SELECT t.[Time]
FROM mytable t
GROUP BY t.[Time]
PIVOT t.ticker IN ('Apple', 'Cisco', 'Oracle', 'Microsoft', 'IBM',
'Amazon', 'Alphabet', 'Intel', 'Adobe', 'SAP')
或者,运行 条件聚合,再次明确指定具有 10 个表达式的 10 列。这种方法允许灵活地重命名列,例如后缀 _Value.
SELECT t.Time,
SUM(IIF(t.ticker = 'Apple', t.Price, NULL)) AS CE1_Value,
SUM(IIF(t.ticker = 'Cisco', t.Price, NULL)) AS CE2_Value,
SUM(IIF(t.ticker = 'Oracle', t.Price, NULL)) AS CE3_Value,
...
SUM(IIF(t.ticker = 'Amazon', t.Price, NULL)) AS PE1_Value,
SUM(IIF(t.ticker = 'Alphabet', t.Price, NULL)) AS PE2_Value,
SUM(IIF(t.ticker = 'Intel', t.Price, NULL)) AS PE3_Value,
...
FROM mytable t
GROUP BY t.Time
是否需要将值传递到查询中,正如我在 运行 时在您的 consider ADO parameterization. Alternatively, with DAO (Access' default API) you can save a prepared statement as an Access query object using PARAMETERS
clause and bind values in code using QueryDefs 中所建议的那样。这两种方法都避免了混乱的连接和标点符号,如 mysql 变量中所示。
DAO
SQL (另存为 Access 查询;无引号或连接)
PARAMETERS [DateIn] Date, [Qty_Param] Long,
[CE1_Param] Text, [CE2_Param] Text, [CE3_Param] Text, [CE4_Param] Text, [CE5_Param] Text,
[PE1_Param] Text, [PE2_Param] Text, [PE3_Param] Text, [PE4_Param] Text, [PE5_Param] Text;
SELECT t.DateTr, t.[Time],
[Qty_Param] * SUM(IIF(t.ticker = [CE1_Param], t.Price, NULL)) AS CE1_Value,
[Qty_Param] * SUM(IIF(t.ticker = [CE2_Param], t.Price, NULL)) AS CE2_Value,
[Qty_Param] * SUM(IIF(t.ticker = [CE3_Param], t.Price, NULL)) AS CE3_Value,
...
[Qty_Param] * SUM(IIF(t.ticker = [PE1_Param], t.Price, NULL)) AS PE1_Value,
[Qty_Param] * SUM(IIF(t.ticker = [PE2_Param], t.Price, NULL)) AS PE2_Value,
[Qty_Param] * SUM(IIF(t.ticker = [PE3_Param], t.Price, NULL)) AS PE3_Value,
...
FROM mytable t
WHERE t.DateTr = [DateIn])
GROUP BY t.DateTr, t.[Time]
VBA
Dim db As DAO.Database, rst As DAO.Recordset, qdef As DAO.QueryDef
Set db = CurrentDb
Set qdef = db.QueryDefs("mySavedQuery")
With qdef
.Parameters("DateIn") = CDate("2016-07-22")
.Parameters("Qty_Param") = ###
.Parameters("CE1_Param") = "Apple"
.Parameters("CE2_Param") = "..."
.Parameters("CE3_Param") = "..."
...
.Parameters("PE1_Param") = "Amazon"
.Parameters("PE2_Param") = "..."
.Parameters("PE3_Param") = "..."
...
End With
Set rst = qdef.OpenRecordset()
...
rst.Close: qdef.Close
Set rst = Nothing: Set qdef = Nothing: Set db = Nothing
下面是我最终的工作 SQL 代码。
SELECT Data.Time,
Round(Sum(IIf(Data.Ticker='Apple',Data.price,Null)),2) AS CE1_Value,
Round(Sum(IIf(Data.Ticker='Amazon',Data.price,Null)),2) AS CE2_Value,
Round(Sum(IIf(Data.Ticker='Intel',Data.price,Null)),2) AS PE1_Value,
Round(Sum(IIf(Data.ticker='Microsoft',Data.price,Null)),2) AS PE2_Value
FROM Data
WHERE (((Data.Time)>#12/30/1899 12:20:0#) AND ((Data.DateTr)=#6/18/2019#))
GROUP BY Data.Time, Data.DateTr
HAVING (((Sum(IIf(Data.Ticker='Apple',Data.price,Null))) Is Not Null)
AND ((Sum(IIf(Data.Ticker='Amazon',Data.price,Null))) Is Not Null)
AND ((Sum(IIf(Data.Ticker='Intel',Data.price,Null))) Is Not Null)
AND ((Sum(IIf(Data.ticker='Microsoft',Data.price,Null))) Is Not Null))
ORDER BY Data.Time;
下面 SQL 查询的当前输出是:
Time | SumValue(CE+PE)
2 列 - 确保输出的数量正好是十。
如何将其转置为:
Time | CE1Value | CE2Value |... |CE5Value | PE1Value | ... PE5Value
11 列。
确保同一特定时间的十条记录全部存在,否则跳到下一分钟(下一条记录)。 我假设它是按时间排序的,默认情况下我可以使用 order by - 它是最佳的吗?
针对 MS Access 中的数据使用 windows 中的独立 vbs 文件。
mySQL = "SELECT [Data.Time],"& Quantity &"*Sum([Data.Price]) AS SumOfPrice FROM Data WHERE ( ( [Data.Ticker] Like '"& CE1 &"' Or [Data.Ticker] Like '"& CE2 &"' Or [Data.Ticker] Like '"& CE3 &"' Or [Data.Ticker] Like '"& CE4 &"' Or [Data.Ticker] Like '"& CE5 &"' Or [Data.Ticker] Like '"& PE1 &"' Or [Data.Ticker] Like '"& PE2 &"' Or [Data.Ticker] Like '"& PE3 &"' Or [Data.Ticker] Like '"& PE4 &"' Or [Data.Ticker] Like '"& PE5 &"' ) AND ([Data.DateTr]=#"& DateIn &"#)) GROUP BY [Data.Time] HAVING [Data.Time] > #"& startTime(i) &"# and (((Count([Data.Ticker]))=10))"
例如。为了理解 : 数据table是:
DateTr|Ticker|Time|Price
22July2016|Apple|3:20 AM|15
22July2016|Apple|3:21 AM|16
22July2016|Apple|3:23 AM|14
22July2016|Amazon|3:20 AM|16
22July2016|Amazon|3:21 AM|14
22July2016|Amazon|3:22 AM|14
22July2016|Amazon|3:23 AM|14
例如。 Apple 数据用于 3:22 ,因此请跳过并转到下一个。 但同时要确保——在我的例子中,计数是 2(在本例中是 Apple+Amazon)10。 CE1 = 苹果,PE1 = 亚马逊 早期输出:
3:20|31
3:21|30
3:23|28
需要新输出:
3:20|15|16
3:21|16|14
so on.
代码与CE1、CE2、PE2等匹配
谢谢
如果数据驻留在 MS Access 中,请考虑 crosstab query,您可以使用 PIVOT
子句显式指定 10 列:
TRANSFORM SUM(t.Price) As SumPrice
SELECT t.[Time]
FROM mytable t
GROUP BY t.[Time]
PIVOT t.ticker IN ('Apple', 'Cisco', 'Oracle', 'Microsoft', 'IBM',
'Amazon', 'Alphabet', 'Intel', 'Adobe', 'SAP')
或者,运行 条件聚合,再次明确指定具有 10 个表达式的 10 列。这种方法允许灵活地重命名列,例如后缀 _Value.
SELECT t.Time,
SUM(IIF(t.ticker = 'Apple', t.Price, NULL)) AS CE1_Value,
SUM(IIF(t.ticker = 'Cisco', t.Price, NULL)) AS CE2_Value,
SUM(IIF(t.ticker = 'Oracle', t.Price, NULL)) AS CE3_Value,
...
SUM(IIF(t.ticker = 'Amazon', t.Price, NULL)) AS PE1_Value,
SUM(IIF(t.ticker = 'Alphabet', t.Price, NULL)) AS PE2_Value,
SUM(IIF(t.ticker = 'Intel', t.Price, NULL)) AS PE3_Value,
...
FROM mytable t
GROUP BY t.Time
是否需要将值传递到查询中,正如我在 运行 时在您的 PARAMETERS
clause and bind values in code using QueryDefs 中所建议的那样。这两种方法都避免了混乱的连接和标点符号,如 mysql 变量中所示。
DAO
SQL (另存为 Access 查询;无引号或连接)
PARAMETERS [DateIn] Date, [Qty_Param] Long,
[CE1_Param] Text, [CE2_Param] Text, [CE3_Param] Text, [CE4_Param] Text, [CE5_Param] Text,
[PE1_Param] Text, [PE2_Param] Text, [PE3_Param] Text, [PE4_Param] Text, [PE5_Param] Text;
SELECT t.DateTr, t.[Time],
[Qty_Param] * SUM(IIF(t.ticker = [CE1_Param], t.Price, NULL)) AS CE1_Value,
[Qty_Param] * SUM(IIF(t.ticker = [CE2_Param], t.Price, NULL)) AS CE2_Value,
[Qty_Param] * SUM(IIF(t.ticker = [CE3_Param], t.Price, NULL)) AS CE3_Value,
...
[Qty_Param] * SUM(IIF(t.ticker = [PE1_Param], t.Price, NULL)) AS PE1_Value,
[Qty_Param] * SUM(IIF(t.ticker = [PE2_Param], t.Price, NULL)) AS PE2_Value,
[Qty_Param] * SUM(IIF(t.ticker = [PE3_Param], t.Price, NULL)) AS PE3_Value,
...
FROM mytable t
WHERE t.DateTr = [DateIn])
GROUP BY t.DateTr, t.[Time]
VBA
Dim db As DAO.Database, rst As DAO.Recordset, qdef As DAO.QueryDef
Set db = CurrentDb
Set qdef = db.QueryDefs("mySavedQuery")
With qdef
.Parameters("DateIn") = CDate("2016-07-22")
.Parameters("Qty_Param") = ###
.Parameters("CE1_Param") = "Apple"
.Parameters("CE2_Param") = "..."
.Parameters("CE3_Param") = "..."
...
.Parameters("PE1_Param") = "Amazon"
.Parameters("PE2_Param") = "..."
.Parameters("PE3_Param") = "..."
...
End With
Set rst = qdef.OpenRecordset()
...
rst.Close: qdef.Close
Set rst = Nothing: Set qdef = Nothing: Set db = Nothing
下面是我最终的工作 SQL 代码。
SELECT Data.Time,
Round(Sum(IIf(Data.Ticker='Apple',Data.price,Null)),2) AS CE1_Value,
Round(Sum(IIf(Data.Ticker='Amazon',Data.price,Null)),2) AS CE2_Value,
Round(Sum(IIf(Data.Ticker='Intel',Data.price,Null)),2) AS PE1_Value,
Round(Sum(IIf(Data.ticker='Microsoft',Data.price,Null)),2) AS PE2_Value
FROM Data
WHERE (((Data.Time)>#12/30/1899 12:20:0#) AND ((Data.DateTr)=#6/18/2019#))
GROUP BY Data.Time, Data.DateTr
HAVING (((Sum(IIf(Data.Ticker='Apple',Data.price,Null))) Is Not Null)
AND ((Sum(IIf(Data.Ticker='Amazon',Data.price,Null))) Is Not Null)
AND ((Sum(IIf(Data.Ticker='Intel',Data.price,Null))) Is Not Null)
AND ((Sum(IIf(Data.ticker='Microsoft',Data.price,Null))) Is Not Null))
ORDER BY Data.Time;