#database #ms-access
#База данных #ms-access
Вопрос:
У меня есть база данных с полевой версией. Может быть много записей с одинаковой строкой версии, поэтому, чтобы извлечь имеющиеся у меня версии, я делаю следующее:
SELECT DISTINCT tblSample.Version
FROM tblSample
ORDER BY tblSample.Version DESC;
Вот пример данных:
tblSample.Version
1.1.1000
1.2.1654
1.15.1223
1.2.1654
1.1.1000
Что я получаю после выполнения запроса:
1.2.1654
1.15.1223
1.1.1000
Что я хочу получить, так это (потому что 15, очевидно,> 2 и 1):
1.15.1223
1.2.1654
1.1.1000
Соответственно, следует учитывать и другие октеты.
Комментарии:
1. Ваши данные неправильно структурированы, если вам нужно сортировать по вложенным строкам.
Ответ №1:
В принципе, если вы хотите sort
выполнить x и distinct
выполнить a для y, вам нужно сначала выполнить distinct (отсюда и подзапрос)
Используя следующую функцию (измененную из ответа Фредга в этой теме) Примечание: функция использует функцию разделения, которая, я думаю, здесь уместна.
Public Function ParseText(TextIn As String, X) As Variant
On Error Resume Next
Dim var As Variant
var = Split(TextIn, ".", -1)
ParseText = var(X)
End Function
Вы можете написать этот оператор SQL
SELECT t.Version
FROM
( SELECT Distinct tblSample.Version
FROM tblSample.Version) t
ORDER BY
Cint(ParseText([t.Version],0)) DESC ,
Cint(ParseText([t.Version],1)) DESC ,
Cint(ParseText([t.Version],2)) DESC;
Обновить
Как отметил ХансУп. Вам также необходимо привести к int, чтобы получить правильную сортировку. Вы можете либо сделать это в SQL (как в моем обновленном ответе), либо вы можете сделать это в parseText и вернуть int
Комментарии:
1. Если я что-то не пропустил, этот ответ все равно не будет сортировать 1.15.1223 до 1.2.1654 в порядке убывания.
2. 1 Но вы бы на самом деле использовали этот подход, CF? Мне кажется, что 3 компонента версии по праву принадлежат отдельным числовым полям. Этот атрибут Version похож на один из тех идентификаторов, которые люди создают путем объединения year, Project_ID и так далее. Если вы хотите это, не сохраняйте это; сохраните вложенные элементы и выполните конкатенацию по требованию по мере необходимости.
3. @HansUp. Я согласен, что, вероятно, должно быть три отдельных поля, но, к сожалению, стоимость выполнения этого может не оправдывать ценность этого изменения.
4. До тех пор, пока данные хранятся неправильно, вы рискуете столкнуться с проблемами производительности, поскольку приведенное выше предложение ORDER BY невозможно изменить.
Ответ №2:
То, что вы пытаетесь сделать, аналогично сортировке IP-адресов. Вы можете следовать точно таким же методам, описанным в этой статье, чтобы выполнить то, что вам нужно.
Комментарии:
1. Они не запрашивают отдельные значения… Я думаю, это ключевой момент.
2. Тогда вы должны быть в состоянии интегрировать предложение Конрада Фрикса поместить Distinct в подзапрос. Чтобы упростить работу, вы могли бы сохранить этот подзапрос как отдельный запрос. Обработайте сохраненный запрос как свою базовую таблицу, и все, что я предоставил по ссылке, должно работать оттуда.
Ответ №3:
Сохраните версию в виде 3 числовых полей.
major minor release
1 1 1000
1 2 1654
1 15 1223
1 2 1654
1 1 1000
Затем вы можете сгенерировать версию, отсортированную по вашему желанию, с помощью запроса, когда вам это нужно.
SELECT [major] amp; "." amp; [minor] amp; "." amp; [release] AS Version_num
FROM [SELECT DISTINCT major, minor, release
FROM tblSample]. AS s
ORDER BY s.major DESC , s.minor DESC , s.release DESC;
Комментарии:
1. Ваше решение тоже хорошее, но на данный момент я не могу изменить структуру базы данных. Спасибо!
Ответ №4:
Одним из решений было бы: проанализируйте полученные строки, чтобы извлечь числовые значения, при необходимости поместите перед ними начальные 0 и выведите строку. Например, 1.2.1654 становится 0001.0002.1654 (если вы уверены, что нумерация не будет превышать 4 символов). Код:
Function NormalizeVersion(Inputstring As String) As String
' Creates sortable strings out of version numbers such as 1.6.222
Dim Elements() As String
Dim Counter As Integer
Dim Result As String
Elements = Split(Inputstring, ".")
For Counter = 0 To UBound(Elements)
Select Case Counter
Case 0 'First element
Result = Format(Elements(Counter), "00000")
Case Else 'Followups
Result = Result amp; "." amp; Right("0000" amp; Elements(Counter), 5)
End Select
Next Counter
NormalizeVersion = Result
End Function
(включено улучшение производительности HansUp)
Затем вы можете выполнить сортировку по этому.
Напишите функцию VBA, которая делает это за вас, называемую, например, NormalizeVersion, затем вызовите ее в своем запросе, например (air code):
SELECT DISTINCT NormalizeVersion(tblSample.Version)
FROM tblSample
ORDER BY NormalizeVersion(tblSample.Version) DESC;
(код исправлен после комментария)
Комментарии:
1. Я получил сообщение об ошибке
ORDER BY clause (NormalizeVersion(tblSample.Version)) conflicts with DISTINCT
2. Вот почему я сказал, что это воздушный код. Так что, вероятно, это что-то вроде:
SELECT DISTINCT Normalizeversion(tblSample.Version) FROM tblSample ORDER BY NormalizeVersion(tblSample.Version) DESC;
3. ? Это работает здесь, в примере базы данных, который я только что запустил в Access XP. Смотрите dl.dropbox.com/u/20995033/test.mdb (хотя и с фиктивной функцией VB)
4. Хорошо, но как это решает проблему? Мне все еще нужно избавиться от этих заполняющих нулей. Если я передам этот запрос в качестве источника в list box (который является одним из мест, где я представляю эти данные), то это будет не так просто. Я бы действительно предпочел иметь какой-то предикат, который будет сравнивать две версии. Есть ли какой-нибудь способ?
5.
Format(Elements(Counter), "00000")
выполняется быстрее, чемRight("0000" amp; Elements(Counter), 5)