SQL Выберите вопрос - PullRequest
2 голосов
/ 10 июня 2009

Я использую это в Access 2003. Извините, если это не в том месте, но я надеялся, что кто-то может помочь.

У меня есть таблица с несколькими записями, в которой текстовое поле представляет поле даты. Дата в таком формате, как: «01.06.2009» Мне нужно выбрать все поля из таблицы, но только 6 самых старых строк, попадающих в диапазон для каждой группы:

COUPONS.DocType, COUPONS.PayTo, COUPONS.ContactName, COUPONS.ContactNumber,
COUPONS.DocFooter, COUPONS.PQBName, COUPONS.LetterDate, COUPONS.RetireeFirstName,
COUPONS.RetireeLastName, COUPONS.Address1, COUPONS.Address2, COUPONS.City, 
COUPONS.State, COUPONS.ZIP, COUPONS.PQBSSN, COUPONS.EmployerCode
ordered by the COUPONS.DateDue. 

Мне нравится: выберите только записи с диапазоном дат 01.01.2009 - 01.12.2009, и из них выберите только 6 самых старых записей.

Я немного повозился с этим и мне не повезло. Я знаю, что это довольно просто, но я просто не могу заставить это работать. Вот выбор SQL, который я использую, чтобы получить дату из таблицы.

SELECT COUPONS.DocType, COUPONS.PayTo, COUPONS.ContactName, COUPONS.ContactNumber,
COUPONS.DocFooter, COUPONS.PQBName, COUPONS.LetterDate, COUPONS.RetireeFirstName, 
COUPONS.RetireeLastName, COUPONS.Address1, COUPONS.Address2, COUPONS.City, 
COUPONS.State, COUPONS.ZIP, COUPONS.PQBSSN, COUPONS.EmployerCode, COUPONS.AmountDue, 
COUPONS.DateDue, Right([DateDue],4)+Left([DateDue],2)+Mid([datedue],4,2) AS SORTDATE
FROM COUPONS
ORDER BY COUPONS.DocType, COUPONS.PayTo, COUPONS.ContactName, COUPONS.ContactNumber, 
COUPONS.DocFooter, COUPONS.PQBName, COUPONS.LetterDate, Right([DateDue],4)+Left
([DateDue],2)+Mid([datedue],4,2);

Ответы [ 8 ]

1 голос
/ 10 июня 2009

Мне кажется, я понимаю вашу проблему - позвольте мне дать вам решение, которое не касается решения вашей проблемы с датой - есть несколько решений этой проблемы.

Учитывая эти данные:

   PQBSSN   DATE    PQBNAME
1   1/1/2009    A
1   1/2/2009    A
1   1/3/2009    A
1   1/4/2009    Z
1   1/5/2009    Z
1   1/6/2009    Z
2   1/1/2009    B
2   1/2/2009    B
2   1/3/2009    B
2   1/4/2009    B
2   1/5/2009    B
2   1/6/2009    B
3   1/1/2009    C
3   1/2/2009    C
3   1/3/2009    C
3   1/4/2009    C
3   1/5/2009    C
3   1/6/2009    C

SELECT C1.PQBSSN, C1.PQBNAME, C3.Date
FROM [SELECT DISTINCT CA.PQBSSN, CA.PQBNAME FROM COUPONS AS CA]. AS C1, 
     [SELECT DISTINCT CB.DATE FROM COUPONS AS CB]. AS C3
WHERE C3.DATE IN 
     (SELECT TOP 2 C2.DATE FROM COUPONS AS C2 WHERE C2.PQBSSN = C1.PQBSSN ORDER BY C2.DATE);

Распределение:

Выбор CA дает уникальные строки не датированной информации

Выбор CB дает все даты в таблице

Выбор "WHERE C3.DATE" дает вам даты, которые относятся к каждой соответствующей группе. Вам нужно поставить галочки в ГДЕ этого выбора для каждого независимого поля, если для группирующих строк нет уникального ключа.

Это дает:

   PQBSS PQBNAME Date
    1   A   1/1/2009
    1   Z   1/1/2009
    2   B   1/1/2009
    3   C   1/1/2009
    1   A   1/2/2009
    1   Z   1/2/2009
    2   B   1/2/2009
    3   C   1/2/2009

Я знаю, что это упрощенная версия вашего стола, но я думаю, что он достигает ваших целей.

1 голос
/ 10 июня 2009

Если у вас есть контроль над базой данных, но вы ДОЛЖНЫ использовать текстовую дату, сохраните ваши даты в каноническом формате ODBC:

yyyy-mm-dd               // if there's no time element
yyyy-mm-dd HH:MM:ss      // if time is needed as well

Это имеет несколько явных преимуществ:

  • Для всего мира, для пользователей, которые не находятся в США и думают, что мм-дд-гггг означает дд-мм-гггг
  • Естественно сортирует по дате, поэтому нормальные операторы <и> работают нормально (и эти операции выполняют текстовое сравнение, они никогда не преобразуют текст в дату).
  • Ваш бизнес-уровень, скорее всего, сможет правильно читать даты в этом формате, не корректируя код вообще
  • Если у вас есть поля, в которых нет фактических дат, это не приведет к ошибке CONVERT (), как многие из уже опубликованных предложений. (Например, если вы также имеете дело с грязными значениями, такими как «Следующий вторник» или «Н / Д», которые вы не можете удалить из базы данных.)

Преобразование существующих данных даты - это простое упражнение UPDATE с RIGHT (), LEFT () и т. Д., При условии, что ваши данные текущей даты имеют согласованный формат.

Как только ваши данные сохранены в формате, который может быть запрошен более легко, это простая проблема:

SELECT TOP 6 * FROM mytable WHERE mydate BETWEEN startdate AND enddate ORDER BY mydate DESC

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

Хорошо, я собираюсь сделать попытку вашей проблемы с группировкой:

SELECT DISTINCT DueDate, DocType, PayTo, ContactName, ContactNumber, [...other fields...]
FROM coupons c1
WHERE CDate(c1.DueDate) BETWEEN '01/01/2000' AND '01/01/2009'
  /* Here's where the "grouping" happens--actually just filtering out the others */
  AND (SELECT COUNT(*) FROM coupons c2 WHERE
    CDATE(c1.DueDate) >= CDATE(c2.DueDate)
    AND c2.DocType=c1.DocType
    AND c2.ContactName=c1.ContactName
    AND c2.ContactNumber=c1.ContactNumber
    [...test the other fields...]
    ) <= 6

Я не могу вспомнить все тонкости Jet SQL, чтобы знать, сработает ли этот подзапрос, но я думаю, что это сработает.

1 голос
/ 10 июня 2009

Если вы уверены, что у вас есть строки даты во ВСЕХ ваших строках, самый простой VB для преобразования в значение даты: CDate ([DateDue]). Тем не менее, он потерпит неудачу в NULL.

Итак, вы можете получить самые старые строки с помощью:

Select Top 6 *
From myTable
ORDER BY CDate([DateDue]) ASC
0 голосов
/ 10 июня 2009

ответ не завершен, работа над ним ...

Чтобы повторить проблему: запрос возвращает слишком много строк, вам нужно ТОЛЬКО шесть строк для каждой «группы» различных значений для семи первых шести столбцов, перечисленных в предложении ORDER BY.

У вас уже есть дата выпуска. Вопреки распространенному мнению, нет необходимости приводить к DATETIME, чтобы этот запрос работал. Проблема в том, упорядочиваете ли вы выражение DATETIME или выражение VARCHAR. Вам просто нужны «самые низкие» n значений для КАЖДОЙ ГРУППЫ.

Чтобы получить этот набор результатов в одном запросе, я думаю, что для этого потребуется предикат stopkey со встроенным представлением. Поддерживает ли Access общие выражения таблиц?

например.

WITH cte AS 
( SELECT ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...) AS ROWNUM
       , ...
    FROM COUPONS c
)
SELECT ...
  FROM cte
 WHERE cte.ROWNUM <= 6

-или-

SELECT TOP 6 ... 
  FROM ...
 GROUP
    BY ...

ответ не завершен


образец оператора SQL из OP, переформатированный, чтобы быть «читабельным»:

SELECT c.DocType
     , c.PayTo
     , c.ContactName
     , c.ContactNumber
     , c.DocFooter
     , c.PQBName
     , c.LetterDate
     , c.RetireeFirstName
     , c.RetireeLastName
     , c.Address1
     , c.Address2
     , c.City
     , c.State
     , c.ZIP
     , c.PQBSSN
     , c.EmployerCode
     , c.AmountDue
     , c.DateDue
     , Right(c.[DateDue],4)+Left(c.[DateDue],2)+Mid(c.[DateDue],4,2) AS SORTDATE
  FROM COUPONS c
 ORDER
    BY c.DocType
     , c.PayTo
     , c.ContactName
     , c.ContactNumber
     , c.DocFooter
     , c.PQBName
     , c.LetterDate
     , Right(c.[DateDue],4)+Left(c.[DateDue],2)+Mid(c.[DateDue],4,2)
0 голосов
/ 10 июня 2009

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

После некоторого быстрого поиска в Google, похоже, что в Access есть функция CDate (), которую вы можете использовать для преобразования строковых данных в даты. Во-вторых, как только вы решите эту проблему, реальный запрос на выбор диапазона дат будет выглядеть примерно так (по крайней мере, в Sql Server - синтаксис для Access, вероятно, будет похожим, но может немного отличаться):

SELECT TOP 6 [...]
FROM [...]
WHERE DateDue BETWEEN @BeginDate AND @EndDate
ORDER BY DateDue ASC

Это общее представление о том, как вы можете получить шесть самых старых записей в диапазоне дат.

0 голосов
/ 10 июня 2009

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

как выбрать шесть самых старых дат, если даты представлены в виде символов.

Вам необходимо привести дату в качестве даты и времени, а затем сделать заказ по:

SELECT top 6 CAST(datedue as datetime) as DateDue from test order by DateDue asc
0 голосов
/ 10 июня 2009

Я не эксперт по Access, но я думаю, что вы могли бы использовать «SELEC TOP», если ваша версия Access поддерживает его:

SELECT TOP 6 COUPONS.DocType, COUPONS.PayTo, COUPONS.ContactName, COUPONS.ContactNumber, COUPONS.DocFooter, COUPONS.PQBName, COUPONS.LetterDate, COUPONS.RetireeFirstName, COUPONS.RetireeLastName, COUPONS.Address1, COUPONS.Address2, COUPONS.City, COUPONS.State, COUPONS.ZIP, COUPONS.PQBSSN, COUPONS.EmployerCode, COUPONS.AmountDue, COUPONS.DateDue, Right([DateDue],4)+Left([DateDue],2)+Mid([datedue],4,2) AS SORTDATE FROM COUPONS

ORDER BY Right ([DateDue], 4) + Left ([DateDue], 2) + Mid ([дата], 4,2), COUPONS.DocType, COUPONS.PayTo, COUPONS.ContactName, COUPONS.ContactNumber, COUPONS.DocFooter, COUPONS.PQBName, COUPONS.LetterDate

0 голосов
/ 10 июня 2009

Возможно, вы добавляете значения даты, подобные этому

Right([DateDue],4)+Left([DateDue],2)+Mid([datedue],4,2);

(например: 1996 + 04 + 21 = 2021)

Так что попробуйте это в вашем заказе

Right([DateDue],4),Left([DateDue],2),Mid([datedue],4,2);

Или попробуйте объединить значения, а не добавлять их:

Right([DateDue],4) & Left([DateDue],2) & Mid([datedue],4,2);

(например: 1996 + 04 + 21 = 19960421)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...