0

我想知道是否有可能并且更有效地做一些我目前在代码中做的事情,而不是在 T-SQL 中做。

我有一个包含课程的数据库。每门课程可以有不同的课程,这些课程是在不同地点和不同奖项的课程的变体。

这是我的(简化的)数据库结构和一些示例数据:

CREATE TABLE tblCourse (CourseId int, CourseName varchar(50))
CREATE TABLE tblOffering (OfferingId int, CourseId int, LocationId int, AwardId int)
CREATE TABLE tblLocation (LocationId int, LocationName varchar(50))
CREATE TABLE tblAward (AwardId int, AwardName varchar(50))

INSERT INTO tblCourse VALUES (1, 'Course A')
INSERT INTO tblCourse VALUES (2, 'Course B')

INSERT INTO tblOffering VALUES (1, 1, 1, 1)
INSERT INTO tblOffering VALUES (2, 1, 2, 1)
INSERT INTO tblOffering VALUES (3, 1, 3, 1)
INSERT INTO tblOffering VALUES (4, 1, 1, 2)
INSERT INTO tblOffering VALUES (5, 2, 3, 1)

INSERT INTO tblLocation VALUES (1, 'Location A')
INSERT INTO tblLocation VALUES (2, 'Location B')
INSERT INTO tblLocation VALUES (3, 'Location C')

INSERT INTO tblAward VALUES (1, 'Award A')
INSERT INTO tblAward VALUES (2, 'Award B')

我想从 SQL 中检索的是每个课程/奖励组合的单行。每行都有每个位置的列,以及该 CourseId/AwardId 组合的课程是否可用。现在将有没有提供的课程/奖励组合的行。

来自示例数据的所需结果将是这样的记录集:

CourseId | CourseName | AwardId | AwardName | LocationA | LocationB | LocationC
---------+------------+---------+-----------+-----------+-----------+----------
1        | Course A   | 1       | Award A   | True      | True      | True
1        | Course A   | 2       | Award B   | True      | NULL      | NULL
2        | Course B   | 1       | Award A   | NULL      | NULL      | True

(NULL 也可能是 False)

目前,我正在做一个带有各种 JOINS 的简单 SELECT 语句,它为每个课程/奖励组合提供了多行,然后我遍历代码中的所有行并构建所需的结果。但是,我认为这不是那么有效,因为我还需要对结果进行分页。

我想我可以通过创建一个临时表和一堆单独的查询在存储过程中相当容易地做到这一点,但我认为这不会太有效。想知道在 T-SQL 中是否有更好的方法?

所以澄清一下,我正在寻找的是一个 T-SQL 查询或存储过程,它将产生上述示例记录集,并且我可以调整分页。

注意。我正在使用 SQL Server 2008

4

3 回答 3

4

对于动态列:

DECLARE  @COLUMNS VARCHAR(max)
        ,@query varchar(1024)
        ,@True varchar(6)


SELECT @COLUMNS = 
COALESCE(
@Columns + ',[' + L.LocationName + ']',
'[' + L.LocationName +']'
)
FROM tblLocation L

SELECT @True = '''True'''

SELECT @QUERY = 'SELECT C.CourseName
                 ,A.AwardName
                 , pvt.*
FROM (SELECT O.OfferingID AS OID
            ,O.AwardID AS AID
            ,O.CourseID AS CID
            ,L.LocationName AS LID
       FROM tblOffering O Inner Join tblLocation L on L.LocationID = O.LocationID) AS S
PIVOT
(
    count(oID) For LID IN (' +@COLUMNS+ ')
) As pvt
inner join tblCourse C on C.CourseID = CID
inner join tblAward A on A.AwardID = pvt.AID'

EXEC (@QUERY)
GO
于 2012-08-23T01:49:23.430 回答
3

这将生成示例结果的分页版本:

declare @tblCourse as table (CourseId int, CourseName varchar(50)) 
declare @tblOffering as table (OfferingId int, CourseId int, LocationId int, AwardId int) 
declare @tblLocation as table (LocationId int, LocationName varchar(50))
declare @tblAward as table (AwardId int, AwardName varchar(50)) 

INSERT INTO @tblCourse VALUES (1, 'Course A') 
INSERT INTO @tblCourse VALUES (2, 'Course B') 

INSERT INTO @tblOffering VALUES (1, 1, 1, 1) 
INSERT INTO @tblOffering VALUES (2, 1, 2, 1) 
INSERT INTO @tblOffering VALUES (3, 1, 3, 1) 
INSERT INTO @tblOffering VALUES (4, 1, 1, 2) 
INSERT INTO @tblOffering VALUES (5, 2, 3, 1) 

INSERT INTO @tblLocation VALUES (1, 'Location A') 
INSERT INTO @tblLocation VALUES (2, 'Location B') 
INSERT INTO @tblLocation VALUES (3, 'Location C') 

INSERT INTO @tblAward VALUES (1, 'Award A') 
INSERT INTO @tblAward VALUES (2, 'Award B') -- This had id 1 in your example.

-- Set the following parameters to control paging:
declare @PageSize as Int = 5
declare @PageNumber as Int = 1

; with CourseAwardSummary as (
  select distinct C.CourseId, C.CourseName, A.AwardId, A.AwardName,
    case when exists ( select 42 from @tblOffering where CourseId = C.CourseId and AwardId = A.AwardId and LocationId = 1 ) then 'True' end as LocationA,
    case when exists ( select 42 from @tblOffering where CourseId = C.CourseId and AwardId = A.AwardId and LocationId = 2 ) then 'True' end as LocationB,
    case when exists ( select 42 from @tblOffering where CourseId = C.CourseId and AwardId = A.AwardId and LocationId = 3 ) then 'True' end as LocationC
  from @tblCourse as C inner join
    @tblOffering as O on O.CourseId = C.CourseId inner join
    @tblAward as A on A.AwardId = O.AwardId
    ),
  CourseAwardSummaryRows as (
    select *, Row_Number() over ( order by CourseName, AwardName ) as RowNumber
      from CourseAwardSummary
    )
    select CourseId, CourseName, AwardId, AwardName, LocationA, LocationB, LocationC
  from CourseAwardSummaryRows
  where ( @PageNumber - 1 ) * @PageSize + 1 <= RowNumber and RowNumber <= @PageNumber * @PageSize
  order by CourseName, AwardName
于 2012-08-23T01:48:26.973 回答
1

以下查询通过连接和聚合提供表,然后将结果连接到课程表和奖励表来完成此操作:

select c.CourseId, c.CourseName, oa.AwardId, oa.AwardName,
       oa.LocationA, oa.LocationB, oa.LocationC
from tblCourse c left outer join
     (select o.CourseId, o.AwardId, a.awardName
             max(case when LocationName = 'Location A' then 'true' end) as LocationA,
             max(case when LocationName = 'Location B' then 'true' end) as LocationB,
             max(case when LocationName = 'Location C' then 'true' end) as LocationC
      from tblOffering o join
           tblLocation l
           on o.LocationId = l.LocationId join
           tblAward a
           on a.awardID = o.AwardId
      group by o.CourseId, o.AwardId, a.awardName
     ) oa
     on oa.CourseId = c.CourseId
于 2012-08-23T01:55:10.757 回答