Параметр datetime хранимой процедуры SQL Server при выборе данных - PullRequest
0 голосов
/ 05 марта 2012

У меня есть база данных футбольной лиги, и я пытаюсь получить текущий счет команд на конкретную дату. Если я введу дату в прошлом, я хочу набрать очки на эту конкретную дату - очки каждой команды на эту дату.

В моей базе данных есть таблица, которая включает все матчи, и у меня есть таблица с командами и их очками (эта таблица фактически совпадает с текущим счетом).

Две таблицы:

 create table teams
 (
 id char(3) primary key,
 name varchar(40),
 nomatches int,
 owngoals int,
 othergoals int,
 points int
 )

 create table matches
 (
 id int identity(1,1),
 homeid char(3) foreign key references teams(id),
 outid char(3) foreign key references teams(id),
 homegoal int,
 outgoal int,
 matchdate datetime
 )

Я пытаюсь использовать хранимую процедуру, где у меня есть datetime в качестве параметра, чтобы показать текущий счет (таблица команды) на ту дату, определенную параметром.

Прямо сейчас я выбираю все матчи, которые больше (новее), чем дата, из которой я хочу получить таблицу результатов, и вычитаю результат этого матча из очков команд.

Но мне кажется, что нужно сделать что-то такое простое.

У кого-нибудь есть идея получше?

Ответы [ 3 ]

0 голосов
/ 05 марта 2012

Я не уверен, почему вы захотите поместить такой простой запрос в процедуру, но, по сути, вы спрашиваете следующее:

CREATE PROCEDURE sp_goals_to_date(@todate DATETIME) AS    
    SELECT id, SUM(homegoal) AS homegoal, SUM(outgoal) AS outgoal FROM matches WHERE matchdate <= @mydate

То, что Федор говорит правильно - этоболее эффективно выполнить один расчет с начала времени, чем выполнять расчет из двух разных таблиц.

0 голосов
/ 06 марта 2012

Я бы сначала преобразовал таблицу matches так:

SELECT
  teamid    = CASE t.calchometeam WHEN 1 THEN m.homeid   ELSE m.outid   END,
  owngoal   = CASE t.calchometeam WHEN 1 THEN m.homegoal ELSE m.outgoal END,
  othergoal = CASE t.calchometeam WHEN 0 THEN m.homegoal ELSE m.outgoal END,
  points    = CASE m.homegoal
    WHEN m.outgoal THEN @drawpoints
    ELSE (SIGN(m.homegoal - m.outgoal) + 1) / 2 ^ ~m.playedhome) * @winpoints
       + (SIGN(m.homegoal - m.outgoal) + 1) / 2 ^ m.playedhome) * @losspoints
  END
FROM matches m
CROSS JOIN (
  SELECT CAST(0 AS bit) UNION ALL
  SELECT CAST(1 AS bit)
) AS t (calchometeam)
WHERE m.matchdate <= @givendate

Теперь проще рассчитать необходимые итоги:

SELECT
  teamid,
  nomatches  = COUNT(*),
  owngoals   = SUM(owngoal),
  othergoals = SUM(othergoal),
  points     = SUM(points)
FROM transformed_matches
GROUP BY
  teamid

Следующим шагом будет присоединение последнего набора результатов к таблице teams, чтобы получить имена команд. И если вам действительно нужен этот последний шаг, вы, конечно, могли бы выполнять вычисления так, как вы планировали с самого начала, то есть рассчитывать только те статистические данные, которые вам нужны для вычитания из текущих значений, а не фактические показатели. Таким образом, используя эту инвертированную логику, весь запрос может выглядеть так:

WITH
transformed_matches AS (
  SELECT
    matchid   = m.id,
    teamid    = CASE t.calchometeam WHEN 1 THEN m.homeid   ELSE m.outid   END,
    owngoal   = CASE t.calchometeam WHEN 1 THEN m.homegoal ELSE m.outgoal END,
    othergoal = CASE t.calchometeam WHEN 0 THEN m.homegoal ELSE m.outgoal END,
    points    = CASE m.homegoal
      WHEN m.outgoal THEN @drawpoints
      ELSE (SIGN(m.homegoal - m.outgoal) + 1) / 2 ^ ~m.playedhome) * @winpoints
         + (SIGN(m.homegoal - m.outgoal) + 1) / 2 ^ m.playedhome) * @losspoints
    END
  FROM matches m
  CROSS JOIN (
    SELECT CAST(0 AS bit) UNION ALL
    SELECT CAST(1 AS bit)
  ) AS t (calchometeam)
  WHERE m.matchdate > @givendate
),
aggregated AS (
  SELECT
    teamid,
    nomatches  = COUNT(*),
    owngoals   = SUM(owngoal),
    othergoals = SUM(othergoal),
    points     = SUM(points)
  FROM transformed_matches
  GROUP BY
    teamid
)
SELECT
  t.id,
  t.name,
  nomatches  = t.nomatches  - ISNULL(a.nomatches , 0),
  owngoals   = t.owngoals   - ISNULL(a.orngoals  , 0),
  othergoals = t.nomatches  - ISNULL(a.othergoals, 0),
  points     = t.points     - ISNULL(a.points    , 0)
FROM teams t
  LEFT JOIN aggregated a ON t.id = a.teamid

Примечание. Вы не указали, какой тип футбола вы имели в виду, но, живя в Европе, мне было легче принять участие в футбольном матче, чем в любом другом виде. Тем не менее, поскольку я не был уверен, я решил параметризовать свой запрос. Вот почему вы можете видеть все эти @winpoints, @drawpoints и @losspoints заполнители. Вы можете заменить переменные фактическими константами, если хотите, или оставить параметризованный запрос на тот случай, если вы хотите удовлетворить свое любопытство относительно того, каково было бы положение команды, если бы действовала другая система подсчета очков.

0 голосов
/ 05 марта 2012

Почему вы вычитаете? Мне кажется, что правильным способом было бы взять дату начала лиги и рассчитать результаты с этого дня до выбранной даты.

...