用于在SQL转换查询中指定列的调用函数

用于在SQL转换查询中指定列的调用函数,sql,ms-access,function-call,Sql,Ms Access,Function Call,我的问题是: PARAMETERS ... TRANSFORM ... SELECT ... ... PIVOT Mytable.type In ("Other","Info"); 这是一个交叉查询,我需要设置此行的所有列标题:PIVOT Mytable.type In(“其他”,“信息”),现在我已经硬编码了标题,Other和Info 但我想动态地这样做。所以我想做的是调用一个vba函数,它返回我需要的所有标题 大概是这样的: PIVOT Mytable.type In (myVbaFunc

我的问题是:

PARAMETERS ...
TRANSFORM ...
SELECT ...
...
PIVOT Mytable.type In ("Other","Info");
这是一个交叉查询,我需要设置此行的所有列标题:
PIVOT Mytable.type In(“其他”,“信息”)
,现在我已经硬编码了标题,OtherInfo

但我想动态地这样做。所以我想做的是调用一个vba函数,它返回我需要的所有标题

大概是这样的:

PIVOT Mytable.type In (myVbaFunction());

因此,我的问题是:如何在sql查询中调用vba函数?

正如您所说,您正在使用Access,那么(我想不出)是的,可以在查询中使用vba函数

查看文档和MSDN。

是的,这是可能的。
但是,我认为,
在(…)中的位置是不可能的。

下面是一个普通
查询的示例,其中
查询:

Public Function Test() As String
    Test = "Smith"
End Function
…然后:

SELECT * FROM Users WHERE Name = Test();
只要函数只返回一个值,它就可以工作。
但我认为不可能让函数返回类似“Smith,Miller”的内容,并使用如下方式:

SELECT * FROM Users WHERE Name In (Test());

(至少我不知道怎么做)

为什么不在表中添加这些标题,并在xtab查询中加入该表?

在函数中对其进行硬编码可能更容易。

如果PIVOT子句中排除了in列表,则转换查询会自动为SELECT语句生成的每个PIVOT值创建列。可以通过使用“硬编码”(即文字)值指定IN表达式来过滤最后的列。当然,从其他答案中可以看出这一点

通过将SELECT查询中的数据限制为从。。。在转换之前,需要对其进行过滤。通过这种方式,不仅限于预定义的文字值,联接、子查询和/或VBA函数的组合还可以预过滤数据,有效地选择转换表中出现的列。请注意,HAVING子句在转换查询中是不允许的,但它可以用于转换随后选择打开的另一个查询中,因此在转换之前如何准备数据实际上没有限制

以下所有操作都会产生相同的结果。首先在中使用PIVOT…:

TRANSFORM Count(Services.ID) AS [Schedules]
SELECT Agreement.City FROM Agreement INNER JOIN Services ON Agreement.Account = Services.Account
WHERE ( Services.Code = "IS" )
GROUP BY Agreement.City ORDER BY Agreement.City
PIVOT Month([ServiceDate]) In (1,4,12)
在WHERE子句中使用IN运算符:

TRANSFORM Count(Services.ID) AS [Schedules]
SELECT Agreement.City FROM Agreement INNER JOIN Services ON Agreement.Account = Services.Account
WHERE ( (Month([ServiceDate]) In (1,4,12)) AND Services.Code = "IS" )
GROUP BY Agreement.City ORDER BY Agreement.City
PIVOT Month([ServiceDate])
但与PIVOT…IN子句不同,列表也可以是另一个查询:

WHERE ((Month([ServiceDate]) In (SELECT Values FROM PivotValues)) AND Services.Code = "IS" )
最后,使用VBA函数(回答原始问题):

使用标准模块中定义的VBA函数:

Public Function ReportMonth(dt As Date) As Boolean
  Select Case Month(dt)
    Case 1, 4, 12: ReportMonth= True
    Case Else:     ReportMonth= False
  End Select
End Function

(iDevlop已经在一篇评论中提出了这个解决方案,但我认为它没有被理解,需要好的例子。)

保证转换中包含列

Andre指出,我的上一个回答未能解决显式透视列列表的一个特征,即即使数据不包含相应的值,它也会显示列。在许多情况下,正如David W Fenton所评论的那样,“动态地”生成完整的SQL也是一样的。下面是一些用于执行此操作的模板代码:

Public Function GenerateTransform(valueArray As Variant) As String
  Dim sIN As String
  Dim i As Integer, delimit As Boolean

  If (VarType(valueArray) And vbArray) = vbArray Then
    For i = LBound(valueArray) To UBound(valueArray)
      sIN = sIN & IIf(delimit, ",", "") & valueArray(i)
      delimit = True
    Next i
    If Len(sIN) > 0 Then sIN = "IN (" & sIN & ")"
  End If

  GenerateTransform = "TRANSFORM ... SELECT ... PIVOT ... " & sIN

End Function

Public Sub TestGenerateTransform()
  Dim values(0 To 2) As Integer
  values(0) = 1
  values(1) = 4
  values(2) = 12

  Debug.Print GenerateTransform(values)
  Debug.Print GenerateTransform(vbEmpty) 'No column list 
End Sub

与我的另一个答案一样,下面的查询允许人们利用各种技术来选择和过滤条件。这种技术不仅可以保证列,还允许对行^^进行更多的控制

^即使VBA函数仍然可以在SQL中正常使用,Access也不允许在使用VBA执行SQL期间动态添加新行数据。。。行必须基于实际的表行。(从技术上讲,可以使用带有文字值的UNION SELECT来创建行,但这对于大量数据来说是禁止的,并且不利于任何类型的动态列选择。)因此,以下技术需要使用辅助表来定义/选择列值

第一个查询应用选择条件并进行初始分组。如果与我的另一个答案相比,这与原始转换查询基本相同——只是没有转换和透视。保存并命名此查询[1初始聚合]

SELECT Agreement.City, Month([ServiceDate]) AS [Month], Count(Services.ID) AS Schedules
FROM Agreement INNER JOIN Services ON Agreement.Account = Services.Account
WHERE (Services.Code = "IS")
GROUP BY Agreement.City, Month([ServiceDate])
ORDER BY Agreement.City
SELECT RowSource.City AS City
FROM [1 Initial Aggregate] AS RowSource
GROUP BY RowSource.City
ORDER BY RowSource.City
SELECT [2 Row Headings].City AS City, PivotValues.Values AS Months
FROM [2 Row Headings], PivotValues
ORDER BY [2 Row Headings].City, PivotValues.Values;
接下来创建一个查询,对所有所需的行值进行分组。在本例中,我选择仅包含初始选择条件中相同的值。^通过基于未过滤的表或其他查询,还可以将这组值与以前的选择条件分离。保存并命名此查询[2行标题]

SELECT Agreement.City, Month([ServiceDate]) AS [Month], Count(Services.ID) AS Schedules
FROM Agreement INNER JOIN Services ON Agreement.Account = Services.Account
WHERE (Services.Code = "IS")
GROUP BY Agreement.City, Month([ServiceDate])
ORDER BY Agreement.City
SELECT RowSource.City AS City
FROM [1 Initial Aggregate] AS RowSource
GROUP BY RowSource.City
ORDER BY RowSource.City
SELECT [2 Row Headings].City AS City, PivotValues.Values AS Months
FROM [2 Row Headings], PivotValues
ORDER BY [2 Row Headings].City, PivotValues.Values;
创建行标题和包含列标题的辅助表[PivotValues]的交叉联接。交叉联接从两个表的每个组合中创建行——在Access SQL中,它是通过排除所有联接关键字来实现的。保存并命名此查询[3交叉联接]

SELECT Agreement.City, Month([ServiceDate]) AS [Month], Count(Services.ID) AS Schedules
FROM Agreement INNER JOIN Services ON Agreement.Account = Services.Account
WHERE (Services.Code = "IS")
GROUP BY Agreement.City, Month([ServiceDate])
ORDER BY Agreement.City
SELECT RowSource.City AS City
FROM [1 Initial Aggregate] AS RowSource
GROUP BY RowSource.City
ORDER BY RowSource.City
SELECT [2 Row Headings].City AS City, PivotValues.Values AS Months
FROM [2 Row Headings], PivotValues
ORDER BY [2 Row Headings].City, PivotValues.Values;
最后,转换:通过使用左连接,这将包括交叉连接查询中存在的所有列和行。对于联接的select查询中缺少数据的列和行对,仍将包括该列(即保证),值为Null。尽管我们已经对初始查询进行了分组,但转换仍然要求我们重新分组——可能有点冗余,但这并不是什么大问题,以获得对最终交叉表结果的所需控制

TRANSFORM Sum([1 Initial Aggregate].Schedules) AS SumOfSchedules
SELECT [3 Cross Join].City AS City
FROM [3 Cross Join] LEFT JOIN [1 Initial Aggregate] ON ([3 Cross Join].Months = [1 Initial Aggregate].Month) AND ([3 Cross Join].City = [1 Initial Aggregate].City)
GROUP BY [3 Cross Join].City
PIVOT [3 Cross Join].Months

仅仅为了使交叉表列成为动态的,这似乎有些过分,但是定义一些额外的查询来完全控制结果是值得的。VBA代码可用于(重新)定义辅助表中的值,从而满足使用VBA动态指定列的原始问题。

您知道我应该如何进行调用,或者在比MSDN更具体的地方,我可以找到有关此的更多信息吗?因为格式必须是
PIVOT Mytable.type in(“标题1”,“标题2”)
并使用
透视Mytable.type In(从Mytable中选择名称)
我不了解该格式。好的,但如果您加入一个包含