JDatabase를 사용하여 하위 쿼리를 만드는 방법


31

에서 http://docs.joomla.org/Selecting_data_using_JDatabase , JDatabase를 사용하여 하위 쿼리를 작성하기위한 문서화 된 방법이 없습니다.

https://gist.github.com/gunjanpatel/8663333 은이를 수행하는 한 가지 방법을 보여줍니다 (몇 비트는 생략 됨).

$subQuery = $db->getQuery(true);
$query    = $db->getQuery(true);

// Create the base subQuery select statement.
$subQuery->select('*')
    ->from($db->quoteName('#__sub_table'))
    ->where($db->quoteName('subTest') . ' = ' . $db->quote('1'));

// Create the base select statement.
$query->select('*')
    ->from($db->quoteName('#__table'))
    ->where($db->quoteName('state') . ' = ' . $db->quote('1'))
    ->where($db->quoteName('subCheckIn') . ' IN (' . $subQuery->__toString() . ')')
    ->order($db->quoteName('ordering') . ' ASC');

// Set the query and load the result.
$db->setQuery($query);

이것은 좋은, 그럴듯한 접근법처럼 보이지만 더 나은 접근법이 있습니까?


4
$ subQuery에서 toString () 호출을 생략 할 수 있습니다. 줌라! 자동으로 처리합니다. 그 외에도이 동일한 방법을 사용하고 나에게 잘 작동합니다.
Zachary Draper


@ZacharyDraper가 재미있다. 이를 담당하는 코드를 보여줄 수 있습니까?
Dmitry Rekun

3
@ZacharyDraper : Joomla! 자체가 아닌 PHP가이를 처리합니다 ( __toString())는 "매직"방법입니다.
MrWhite

네, w3d 감사합니다.
Zachary Draper

답변:


16

그렇습니다. 관심있는 한 하위 쿼리를 작성하는 방법은 대부분의 Joomla 확장 프로그램 개발자가 채택한 것입니다.

고객을 위해 만든 내 확장 및 사용자 지정 확장에 동일한 방법을 사용합니다.

이 작업을 수행하는 "공식적인"방법은 없지만 표시 한대로 수행하면 쿼리 빌더를 사용하고 여전히 가독성을 유지할 수 있습니다.


10

AFAIK는 쉬운 하위 쿼리를 수행 할 수있는 방법이 내장되어 있지 않습니다. 이는 시스템의 결함 일 수 있으며 PR을 통해 수정해야합니다.

그러나 귀하의 예에는 아무런 문제가 없습니다.

~~~

다음은 @DavidFritsch의 의견에 대한 응답의 예입니다. 내가 생각할수록 OP에 표시되는 더 간단한 접근 방식이 더 좋습니다. 무슨 일이 일어나고 있는지 더 분명합니다.

$query = $this->db->getQuery(true)
  ->select('a.*')
  ->subQuery()
    ->select('b.*')
    ->from('#__table_b AS b')
    ->as('subQueryResult')
  ->endSubQuery()
  ->from('#__table_a AS a');

1
이것이 어떻게 작동하는지 알 수 있습니까? 하나의 쿼리 객체 에서이 작업을 수행하는 데 사용할 형식을 상상하려고하지만 실제로이 방법보다 쉬운 것은 없습니다.
David Fritsch

1
subQuerySelect좀 더 "깨끗하게"할 수 있는 방법 을 만드는 것이 좋습니다 . 제공 및 예를 위해 답변을 편집하겠습니다.
Don Gilbert

나는 Joomla
fruppel

3

Joomla Platform API를 사용하여 하위 쿼리가 포함 된 쿼리를 실행하는 방법도 있습니다. 하위 쿼리 사용 방법에 대한 기본 아이디어는 gunjanpatel을 기반으로 합니다 .

다음은 중첩 집합 모델 에서 쿼리를 실행하는 예입니다 .

SQL 쿼리 :

-- Find the Immediate Subordinates of a Node
SELECT node.title, (COUNT(parent.id) - (sub_tree.depth + 1)) AS depth
FROM lubd3_usergroups AS node,
        lubd3_usergroups AS parent,
        lubd3_usergroups AS sub_parent,
        (
                SELECT node.id, (COUNT(parent.id) - 1) AS depth
                FROM lubd3_usergroups AS node,
                        lubd3_usergroups AS parent
                WHERE node.lft BETWEEN parent.lft AND parent.rgt
                        AND node.id = 1
                GROUP BY node.id
                ORDER BY node.lft
        )AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
        AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
        AND sub_parent.id = sub_tree.id
GROUP BY node.id
-- not showing the parent node
HAVING depth = 1
-- showing the parent node
-- HAVING depth <= 1
ORDER BY node.lft;

Joomla가 실행하는 변환 된 쿼리 :

// Create the subQuery select statement.
// Nested Set Queries: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
// CROSS JOIN: http://www.informit.com/articles/article.aspx?p=30875&seqNum=5
$subQuery->select(array('node.id', '(COUNT(parent.id) - 1) AS depth'))
    ->from($db->quoteName('#__usergroups') . 'node')
    ->join('CROSS', $db->quoteName('#__usergroups', 'parent'))
    ->where($db->quoteName('node.lft') . ' BETWEEN  ' . $db->quoteName('parent.lft') . ' AND ' . $db->quoteName('parent.rgt') . ' AND ' . $db->quoteName('node.id') . ' = ' . $db->quote('1'))
    ->group($db->quoteName('node.id'))
    ->order($db->quoteName('node.lft'));

// Create the base select statement.
$query->select(array('node.title', '(COUNT(parent.id) - (sub_tree.depth + 1)) AS depth'))
    ->from($db->quoteName('#__usergroups') . 'node')
    ->join('CROSS', $db->quoteName('#__usergroups', 'parent'))
    ->join('CROSS', $db->quoteName('#__usergroups', 'sub_parent'))
    ->join('CROSS', '(' . $subQuery .') AS sub_tree')
    ->where($db->quoteName('node.lft') . ' BETWEEN  ' . $db->quoteName('parent.lft') . ' AND ' . $db->quoteName('parent.rgt')
    . ' AND ' . $db->quoteName('node.lft') . ' BETWEEN  ' . $db->quoteName('sub_parent.lft') . ' AND ' . $db->quoteName('sub_parent.rgt')
    . ' AND ' . $db->quoteName('sub_parent.id') . ' = ' . $db->quoteName('sub_tree.id'))
    ->group($db->quoteName('node.id'))
    ->having($db->quoteName('depth') . ' = ' . $db->quote('1'))
    ->order($db->quoteName('node.lft'));

// Set the query and load the result.
$db->setQuery($query);
$rowList = $db->loadAssocList();

echo "<pre>";
print_r($rowList);
echo "</pre>";

1
좋아 보이지만 OP의 예와 완전히 같습니다. 하위 쿼리를 먼저 만든 다음 기본 쿼리에서 사용하십시오. 더 좋은 방법이 있는지에 대한 질문이었습니다.
fruppel

1

내 스 니펫 버전을 제공 한 다음 정당성을 설명하고 Joomla Coding Standards 매뉴얼 ( 따옴표 블록 형식으로 표시됨)의 따옴표를 포함 시킵니다.

$subquery = $db->getQuery(true)
    ->select("checkin")
    ->from("#__sub_table")
    ->where("subTest = 1");

$query = $db->getQuery(true)
    ->select("*")
    ->from("#__table")
    ->where([
        "state = 1",
        "subCheckIn IN ({$subQuery})"
    ])
    ->order("ordering");

$db->setQuery($query);

쿼리 체인을 사용하여 여러 쿼리 메서드를 하나씩 연결하면 각 메서드는 다음 메서드를 지원할 수있는 개체를 반환하므로 가독성이 향상되고 결과 코드가 간소화됩니다.

  • 가장 안쪽 쿼리를 먼저 작성하고 가장 바깥 쪽 쿼리로 진행합니다. 이를 통해 모든 쿼리 작성 메소드를 메소드에 직접 연결할 수 getQuery()있습니다. 효과적으로, 개별 쿼리를 작성하는 동안 변수 이름은 한 번만 작성됩니다.
    다음은 무거운 쿼리 중첩의 훌륭한 예입니다 (체인 화살표를 정렬하는 것이 귀엽다고 생각했을 때).

  • 경험이 적은 개발자의 혼동으로 이어질 수 있기 때문에 동일한 쿼리 내에서 여러 번 select()및 / 또는 where()전화를 걸지 않으려 고 노력합니다 . 이러한 메소드는 배열을 허용하므로 더 읽기 쉽고 더 나은 코딩 방법을 사용합니다.

  • 마지막으로 가장 논란이 많은 주제는 ...

    테이블 이름과 테이블 열 이름은 항상 quoteName () 메소드로 묶어야 테이블 이름과 테이블 열을 이스케이프해야합니다. 쿼리에서 확인 된 필드 값은 데이터베이스로 전달하기 전에 항상 quote () 메소드로 묶어 값을 이스케이프해야합니다. 쿼리에서 확인 된 정수 필드 값도 (int)로 캐스트되어야합니다.

    나는이 입장에서 매우 갈등합니다. 작년에 Joomla에 처음 왔을 때 나는 정적 값에 대해 쓸모없는 호출 (안정성, 보안, 쿼리의 가독성에 이점이 없음)을 만들지 않을 것이라고 생각했습니다! 하지만, 내 고용주는 줌라 라인을 토인의 아이디어를 좋아하고, 내가 일반적으로 규칙에 대한 높은 인식을 가지고 있음을 인정해야 내가 내 쿼리를 뿌리기 된 있도록 quote(), (int)그리고 quoteName()이는 모든 (문자열 연결의 힙을 의미 제대로 간격을 두십시오). 내 작품의 최종 결과는 엄청나게 부풀어 오른 쿼리 블록으로 인해 심지어 눈이 번거 롭습니다. 수직 스태킹에 적합하지 않은 최악의 / 가장 긴 줄 join()은 테이블 이름, 별칭 및 ON따옴표가 필요하거나 필요하지 않은 하나 이상의 조건 으로 인한 호출 입니다.이 정책은 초보 개발자를 위해 보안을 염두에두고 구현되었다는 점을 이해할 수 있지만 모든 Joomla 코더가 무식한 복사 붙여 넣기가 아니라는 점에서이 정책이 어떤 식 으로든 강화 되었으면 좋겠습니다. 불필요한 호출없이 코드가 얼마나 깨끗하고 간결한 지 살펴보십시오.

  • 걸레질에 관해서는 :

    • 나는 *SELECT 절에서 거의 사용하지 않습니다.
    • 난 절대 전화하지 않아 __toString()
    • 정수를 인용하지 않고 정수로 캐스트합니다.
    • 이것이 ASC기본 정렬 방향이기 때문에 쓰지 않습니다.
    • 새 테이블 이름과 열 이름을 만들 때 mysql 키워드를 사용하지 않도록 모든 노력을 기울입니다.
    • 개인적 선호의 문제로, 나는 일관성을 유지하고 mysql의 작은 따옴표와 구별하기 위해 메소드의 문자열 인수에 큰 따옴표를 사용하는 경향이 있으며 " 복잡한 구문 "으로 일반적으로 쓰는 변수 보간을 즐길 수 있습니다 .
    • 정보 질의 변수 이름과 주석을 사용하여 내포 된 쿼리의 가독성을 높이고 코드는 일반적으로 사용합니다
    • 구금을 떠나기 전에 코드를 테스트합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.