Sql как найти самую раннюю дату

While using TOP or a sub-query both work, I would break the problem into steps:

Find target record

SELECT MIN( date ) AS date, id
FROM myTable
WHERE id = 2
GROUP BY id

Join to get other fields

SELECT mt.id, mt.name, mt.score, mt.date
FROM myTable mt
INNER JOIN
( 
   SELECT MIN( date ) AS date, id
   FROM myTable
   WHERE id = 2
   GROUP BY id
) x ON x.date = mt.date AND x.id = mt.id

While this solution, using derived tables, is longer, it is:

  • Easier to test
  • Self documenting
  • Extendable

It is easier to test as parts of the query can be run standalone.

It is self documenting as the query directly reflects the requirement
ie the derived table lists the row where id = 2 with the earliest date.

It is extendable as if another condition is required, this can be easily added to the derived table.

Есть таблица хранящая линии покупки: Sales: Id, ProductId, CustomerId, DateCreated. Мы хотим понять, через какие продукты клиенты «попадают» к нам в магазин. Как мог бы выглядеть запрос, который выводит продукт и количество случаев, когда он был первой покупкой клиента.

задан 10 авг 2016 в 9:34

OlegK's user avatar

Укажите СУБД.

А вообще примерно так:

SELECT ProductId, COUNT(*) as Cnt
FROM(
  SELECT ProductId, CustomerId, DateCreated, 
    MIN(DateCreated)OVER(PARTITION BY   CustomerId)MinDate
  FROM Sales
)as T
WHERE DateCreated = MinDate
GROUP BY ProductId
ORDER BY COUNT(*) DESC

Если нет оконных функций, то так:

SELECT S.ProductId, COUNT(*) as Cnt
FROM(
  SELECT CustomerId,  
    MIN(DateCreated)MinDate
  FROM Sales
  GROUP BY CustomerId
)as T JOIN Sales as S ON S.CustomerId = T.CustomerId 
  AND S.MinDate=S.DateCreated
GROUP BY S.ProductId
ORDER BY COUNT(*) DESC

ответ дан 10 авг 2016 в 9:46

pegoopik's user avatar

pegoopikpegoopik

3,43014 серебряных знаков51 бронзовый знак

2

Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

. Первый шаг — точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа прекращает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name — null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

  • Избегание операторов «! = null» в Java?

Я все еще не могу найти проблему

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

У меня есть серия дат, связанных с уникальным идентификатором в таблице. Например:

1 | 1999-04-01 | 0000-00-00 | 0000-00-00 | 0000-00-00   | 2008-12-01 | 
2 | 1999-04-06 | 2000-04-01 | 0000-00-00 | 0000-00-00   | 2010-04-03 | 
3 | 1999-01-09 | 0000-00-00 | 0000-00-00 | 0000-00-00   | 2007-09-03 | 
4 | 1999-01-01 | 0000-00-00 | 1997-01-01 | 0000-00-00   | 2002-01-04 | 

Есть ли способ, чтобы выбрать самую раннюю дату из предопределенного списка полей DATE с помощью простой команды SQL?

Таким образом, ожидаемый результат:

1 | 1999-04-01
2 | 1999-04-06
3 | 1998-01-09
4 | 1997-01-01

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

спасибо

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

РЕШЕНИЕ: Используется комбинация LEAST() и IF(), чтобы отфильтровать даты NULL.

 SELECT LEAST( IF(date1=0,NOW(),date1), IF(date2=0,NOW(),date2), [...] );

Извлеченные уроки a) COALESCE не обрабатывает ‘0000-00-00’ как дату NULL, b) LEAST вернет ‘0000-00-00’ как наименьшее значение — я бы предположил, что это связано с внутренним целым сравнением (?)

У меня есть таблица (в MS SQL 2005) с подборкой дат. Я хочу иметь возможность применить оператор WHERE, чтобы вернуть их группу, а затем вернуть, какая дата является самой ранней из одного столбца, а какая — самой поздней из другого столбца. Вот примерная таблица:

ID StartDate  EndDate    Person
1  01/03/2010 03/03/2010 Paul
2  12/05/2010 22/05/2010 Steve
3  04/03/2101 08/03/2010 Paul

Поэтому я хочу вернуть все записи, где Person = ‘Paul’. Но верните что-то вроде (самое раннее) StartDate = 01/03/2010 (из идентификатора записи 1) и (последнее) EndDate = 08/03/2010 (из идентификатора записи 3).

Заранее спасибо

2 ответа

Лучший ответ

Вам понадобятся агрегатные функции min и max, например очень простой случай:

select min(StartDate), max(EndDate)
from data
where Person = 'Paul'

У вас есть все обычные возможности SQL, поэтому доступен выбор из подзапроса.


11

Richard
25 Мар 2010 в 12:13

Было бы неплохо также использовать group by. Итак, если вам нравятся все лица в вашем результате, и вы опускаете предложение where, вы не получите ошибочные данные:

select person, min(StartDate), max(EndDate)
from data
group by person

Или

select person, min(StartDate), max(EndDate)
from data
where person ='Paul'
group by person

Или

select person, min(StartDate), max(EndDate)
from data
group by person
having person ='Paul'


2

Whakkee
25 Мар 2010 в 12:34

Понравилась статья? Поделить с друзьями:
  • Как составить медиакарту на сми
  • Как найти телефон через телефон 900
  • Как на альфе найти искру на
  • Как найти партнера в the trail
  • Как правильно составить судоку