Как проверить свойство в любом из нескольких столбцов, если значение столбца не равно нулю

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

class Payment implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long id;
                
    @JoinColumn(name = "payee_id", referencedColumnName = "id", nullable = true)
    @OneToOne(optional = true)
    private ProductPayee payeeId;
                
    @JoinColumn(name = "allocation_id", referencedColumnName = "id", nullable = true)
    @OneToOne(optional = true)
    private ProductAllocation allocationId;     //  can have value only if no payeeId(ie, when payeeId = null) else null
                
    @JoinColumn(name = "user_id", referencedColumnName = "id", nullable = true)
    @OneToOne(optional = true)
    private Recipient userId;     //  if no payeeId
                
    @Column(name = "amount")
    private Double amount;
}

class ProductPayee implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long id;
                
    @JoinColumn(name = "allocation_id", referencedColumnName = "id", nullable = false)
    @OneToOne(optional = false)
    private ProductAllocation allocationId;
                
    @JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)
    @OneToOne(optional = false)
    private Recipient userId;
                
}                        

class ProductAllocation implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long id;
                
    @JoinColumn(name = "product_id", referencedColumnName = "id", nullable = false)
    @OneToOne(optional = true)
    private Product productId;
                
    @Column(name = "amount")
    private Double amount;
}

class GroupLink implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long id;

    @JoinColumn(name = "group_id", referencedColumnName = "id", nullable = false)
    @OneToOne(optional = true)
    private Group groupId;

    @JoinColumn(name = "product_id", referencedColumnName = "id", nullable = false)
    @OneToOne(optional = false)
    private Product productId;
}

class GroupStaff implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long id;

    @JoinColumn(name = "staff_id", referencedColumnName = "id", nullable = false)
    @OneToOne(optional = false)
    private Staff staffId;

    @JoinColumn(name = "group_id", referencedColumnName = "id", nullable = false)
    @OneToOne(optional = true)
    private Group groupId;
}     

class ProductStaff implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long id;

    @JoinColumn(name = "staff_id", referencedColumnName = "id", nullable = false)
    @OneToOne(optional = false)
    private Staff staffId;

    @JoinColumn(name = "allocation_id", referencedColumnName = "id", nullable = false)
    @OneToOne(optional = false)
    private ProductAllocation allocationId;

    @Column(name = "type")
    private int type; 
}

Получатель, Персонал и Продукт аналогичны обычным таблицам «Персонал» и «Предмет».

Ниже приведен запрос, который я выполняю для получения данных, в которых таблица «Платежи» имеет либо payeeId со значением, либо AllocationId со значением.

Таким образом, (1) если идентификатор payeeId присутствует, то значениеlocationId будет иметь значение null и проверьте значение в ProductPayee, или (2) в противном случае значение locationId присутствует, а затем значение payeeId будет иметь значение null и проверьте таблицу ProductAllocation.

Query query = session.createQuery("FROM Payment where " +
        "(case when payeeId != null then payeeId.allocationId.productId.id else allocationId.productId.id end in (SELECT productId.id from GroupLink where groupId.id in (SELECT groupId.id from GroupStaff where staffId.id = :staffId)) " +
        "OR case when payeeId != null then payeeId.allocationId.id else allocationId.id end in (SELECT allocationId.id FROM ProductStaff WHERE staffId.id = :staffId and type = :resType))) " +
        "order by date desc");

Мне нужно избегать столбца с нулевым значением в предложенииwhere из двух столбцов и искать одно и то же значение в обоих столбцах, которое никогда не является нулевым, любой из двух столбцов всегда имеет нулевое значение.

Вышеуказанный запрос HQL не дает ожидаемого результата при выполнении. Как мне написать это правильно, избегая нулевого регистра в HQL?

ОБНОВЛЯТЬ

Пробовал с COALESCE(payeeId.allocationId.productId.id, allocationId.productId.id) in (Select ...), но все равно большая часть записей отсутствует.

ОБНОВЛЕНИЕ 2:

Я хочу COALESCE(payeeId.allocationId.productId.id,locationId.productId.id), но он будет работать, только если это просто COALESCE(payeeId,locationId). Итак, проблема в том, что если значение locationId равно NULL, то тогдаlocationId.productId. id вернет ошибку. Оператор COALESCE завершит работу, аналогично, если payeeId NULL, то payeeId.allocationId.productId.id приведет к ошибке. Как я могу преодолеть эту ситуацию?

Можете ли вы предоставить более подробную информацию о других объектах, указанных в запросе или упомянутых выше? Я говорю о GroupLink, GroupStaff, ProductStaff или Recipient and Product. Без них сложно воспроизвести поведение запроса.

Francesco Poli 02.09.2024 17:17

Вам нужно придерживаться только HQL? Разве это не может быть собственный запрос?

Asgar 02.09.2024 19:33

@FrancescoPoli Думаю, я предоставил здесь необходимую информацию... обновлю больше, если хочешь..

KJEjava48 03.09.2024 07:40

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

KJEjava48 03.09.2024 07:41

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

Asgar 03.09.2024 07:53

@Asgar Так можешь ли ты помочь мне написать выше, используя собственный запрос??

KJEjava48 03.09.2024 07:55

@FrancescoPoli Я обновил его, добавив больше таблиц... Получатель, Персонал и Продукт похожи на обычные таблицы Person и Item...

KJEjava48 03.09.2024 07:57

@Asgar Мне нужно COALESCE(payeeId.allocationId.productId.id,locationId.productId.id), но это будет работать, только если это просто COALESCE(payeeId,locationId)

KJEjava48 04.09.2024 12:39

Почему бы вам не предоставить примеры таблиц базы данных, примеры данных и желаемый результат? Таким образом, кто-то может помочь и вам с запросом.

Asgar 04.09.2024 16:31
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
9
78
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

если вы используете Hibernate 6.0+, могу ли я предложить использовать предложение UNION в запросе hql вместо case, чтобы помочь разделить различные ограничения, которые необходимо использовать, если поля payeeId или allocationId имеют значение null или нет? Я попытался переписать ваш запрос, используя этот подход, и получил следующее:

"select p from Payment p where p.payeeId is not null and p.allocationId is null and "
          + "( "
          + "p.payeeId.allocationId.productId.id in (SELECT productId.id from GroupLink where groupId.id in (SELECT groupId.id from GroupStaff where staffId.id = :staffId)) "
          + "or "
          + "p.payeeId.allocationId.id in (SELECT allocationId.id FROM ProductStaff WHERE staffId.id = :staffId and type = :resType) "
          + ")"
          + "union "
          + "select p from Payment p where p.payeeId is null and p.allocationId is not null and "
          + "( "
          + "p.allocationId.productId.id in (SELECT productId.id from GroupLink where groupId.id in (SELECT groupId.id from GroupStaff where staffId.id = :staffId)) "
          + "or "
          + "p.allocationId.id in (SELECT allocationId.id FROM ProductStaff WHERE staffId.id = :staffId and type = :resType)"
          + ")"

Как видите, существует union из двух подзапросов: первый возникает, когда payeeId не имеет значения NULL, а второй — когда allocationId не имеет значения NULL. Я просто выполнил условие, чтобы оно не было исключительно нулевым.

В вопросе вы говорите, что «запрос не дает соответствующего результата при выполнении»: какие записи отсутствуют или возвращаются, когда они не должны?

Обновление после комментария «объединиться».

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

  "select p from Payment p "
      + "left join p.payeeId pp left join pp.allocationId ppa left join ppa.productId ppap "
      + "left join p.allocationId pa left join pa.productId pap "
      + "where coalesce(ppap.id, pap.id) in "
      + "    (SELECT productId.id from GroupLink where groupId.id in (SELECT groupId.id from GroupStaff where staffId.id = :staffId)) "
      + "  or coalesce(ppa.id, pa.id) in "
      + "    (SELECT allocationId.id FROM ProductStaff WHERE staffId.id = :staffId and type = :resType)"

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

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

KJEjava48 03.09.2024 11:54

@ KJEjava48 Дело в том, какие записи не являются «подходящими» и почему? Есть дубликаты, недостающие записи или другие проблемы? Я могу предложить начать идентифицировать один из этих случаев и проверить, какое из предложенийwhere не соответствует правильно. Вы можете создать базовый тест JUnit, в котором вы постепенно создадите запрос hql и попытаетесь найти проблему, используя этот инкрементный подход.

Francesco Poli 03.09.2024 12:01

На самом деле отсутствуют некоторые записи всякий раз, когда возникает второй случай..т.е., когда payeeId = null и AllocationId существует... записи до этой точки не вернутся..

KJEjava48 03.09.2024 12:45

Я хочу COALESCE(payeeId.allocationId.productId.id,locationId.productId.id), но он будет работать, только если это просто COALESCE(payeeId,locationId)

KJEjava48 04.09.2024 12:38

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

Francesco Poli 04.09.2024 16:53

Вуаля. Обновленный ответ сработал... Это правильный и простой способ сделать это??? Соединение кажется немного неудобным.

KJEjava48 05.09.2024 07:56

Что ж, при выполнении payeeId.allocationId.productId.id вы неявно указываете движку HQL выполнить соединения между Payment и другими таблицами; то, что я сделал, это просто сказал явно и сделал это в режиме левого соединения, это похоже на необязательную переписку. Я обычно полагаюсь на соединения при работе с sql, потому что (ИМХО) — это более линейный способ просмотра отношений между записями таблицы. Возможно, движок HQL все еще не может разбить сложное выражение, такое как payeeId.allocationId.productId.id, в качестве аргумента объединения, поэтому вам придется направить его к «простой» цели.

Francesco Poli 05.09.2024 08:55

ок. спасибо за ответ

KJEjava48 05.09.2024 08:59

Другие вопросы по теме