it-swarm-vi.com

Phương thức tạo truy vấn con bằng cách sử dụng JDatabase

Tại http://docs.j Joomla.org/Selecting_data_USE_JDatabase , không có phương pháp tài liệu nào để viết một truy vấn con bằng cách sử dụng JDatabase.

https://Gist.github.com/gunjanpatel/86633 minh họa một cách để thực hiện điều này với (một vài bit bị bỏ qua):

$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);

Đây có vẻ là một cách tiếp cận tốt, hợp lý, nhưng có một cách tốt hơn?

31
betweenbrain

Vâng, theo như tôi nghĩ, cách bạn xây dựng truy vấn con là cách mà phần lớn các nhà phát triển tiện ích mở rộng của j Joomla chấp nhận.

Tôi sử dụng phương pháp tương tự trên một số tiện ích mở rộng và tiện ích mở rộng tùy chỉnh được tạo cho khách hàng.

Không có cách "chính thức" để làm việc này, nhưng thực hiện như bạn đã trình bày cho phép bạn sử dụng trình tạo truy vấn và vẫn giữ được mức độ dễ đọc

16
Skullbock

AFAIK không có cách xây dựng để thực hiện các truy vấn con dễ dàng, có lẽ là một thiếu sót trong hệ thống và cần được sửa chữa thông qua PR.

Tuy nhiên, tôi thấy không có vấn đề gì với ví dụ của bạn - có vẻ đủ hợp lý.

~~~

Dưới đây là một ví dụ để phản hồi bình luận của @ DavidFritsch bên dưới. Càng nghĩ nhiều về nó, tôi càng thích cách tiếp cận đơn giản hơn được hiển thị trong OP. Rõ ràng hơn những gì đang xảy ra.

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

Ngoài ra còn có một cách để thực hiện các truy vấn có chứa các truy vấn con bằng cách sử dụng API nền tảng Joomla. Ý tưởng cơ bản về cách sử dụng các truy vấn con dựa trên gunjanpatel .

Dưới đây là một ví dụ để thực hiện các truy vấn trên Các mô hình tập hợp lồng nha :

Truy vấn 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;

và truy vấn được chuyển đổi sẽ được thực hiện bởi 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>";
3
Mario Neubauer

Tôi sẽ cung cấp phiên bản đoạn mã của mình sau đó giải thích lời biện minh của mình và bao gồm các trích dẫn từ hướng dẫn sử dụng tiêu chuẩn mã hóa Joomla (sẽ được định dạng trích dẫn).

$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);

Sử dụng chuỗi truy vấn để kết nối một số phương thức truy vấn, lần lượt từng phương thức, với mỗi phương thức trả về một đối tượng có thể hỗ trợ phương thức tiếp theo, Điều này giúp cải thiện khả năng đọc và đơn giản hóa mã kết quả.

  • Tôi viết các truy vấn trong cùng trước và tiến tới truy vấn ngoài cùng. Điều này cho phép tôi xâu chuỗi tất cả các phương thức xây dựng truy vấn trực tiếp vào phương thức getQuery(). Thực tế, tên biến chỉ được viết một lần trong khi xây dựng truy vấn riêng.
    [.__.] Đây một ví dụ tuyệt vời về một số truy vấn nặng nề lồng nha (khi tôi nghĩ thật dễ thương khi xếp các mũi tên xích).

  • Tôi cố gắng tránh thực hiện nhiều cuộc gọi select() và/hoặc where() trong cùng một truy vấn vì tôi đã thấy nó dẫn đến sự nhầm lẫn của các nhà phát triển ít kinh nghiệm hơn . Bởi vì các phương thức này chấp nhận mảng, tôi thấy nó dễ đọc hơn và thực hành mã hóa tốt hơn để sử dụng chúng.

  • và cuối cùng là chủ đề gây tranh cãi nhất ...

    Tên bảng và tên cột bảng phải luôn được đặt trong phương thức quoteName () để thoát tên bảng và cột bảng. Các giá trị trường được kiểm tra trong một truy vấn phải luôn được đặt trong phương thức quote () để thoát giá trị trước khi chuyển nó vào cơ sở dữ liệu. Các giá trị trường số nguyên được kiểm tra trong một truy vấn cũng phải là kiểu truyền tới (int).

    Tôi rất mâu thuẫn về lập trường này. Khi tôi lần đầu tiên đến Joomla năm ngoái, tôi đã nghĩ, tôi sẽ không thực hiện các cuộc gọi vô ích (không có lợi cho sự ổn định, bảo mật, khả năng đọc của truy vấn) trên các giá trị tĩnh! Tuy nhiên, chủ nhân của tôi thích ý tưởng về việc sử dụng dòng Joomla và tôi phải thừa nhận rằng tôi thường đánh giá cao các quy tắc, vì vậy tôi đã bỏ qua các truy vấn của mình bằng quote(), (int)quoteName() cũng có nghĩa là hàng đống chuỗi nối (tất cả đều cách đều nhau). Kết quả cuối cùng của công việc của tôi là các khối truy vấn cồng kềnh khủng khiếp mà ngay cả tôi cũng có một thời gian khó khăn. Các dòng tệ nhất/dài nhất không cho phép xếp theo chiều dọc là các lệnh gọi join() vì tablename, bí danh, ON, sau đó một hoặc nhiều điều kiện có thể hoặc không yêu cầu trích dẫn Tôi có thể đánh giá cao rằng chính sách này được triển khai với mục đích bảo mật cho các nhà phát triển mới làm quen, nhưng tôi chắc chắn sẽ thích nếu chính sách này bằng cách nào đó có thể cảm nhận được rằng không phải tất cả các lập trình viên Joomla đều là những người sao chép không biết gì . Ý tôi là, hãy xem mã trông gọn gàng và ngắn gọn như thế nào mà không cần các cuộc gọi không cần thiết.

  • Đối với việc lau dọn:

    • Tôi gần như không bao giờ sử dụng * Trong các mệnh đề CHỌN của mình
    • Tôi không bao giờ gọi __toString()
    • Tôi không trích dẫn số nguyên, tôi chọn chúng là số nguyên
    • Tôi không viết ASC vì đó là hướng sắp xếp mặc định
    • Tôi cố gắng hết sức để không sử dụng từ khóa mysql khi tạo tên bảng và tên cột mới
    • Theo sở thích cá nhân, tôi có xu hướng sử dụng trích dẫn kép trên các đối số chuỗi của phương thức của mình để duy trì tính đồng nhất, phân biệt với trích dẫn đơn của mysql và để tôi có thể thưởng thức phép nội suy biến mà tôi thường viết bằng " cú pháp phức tạp ".
    • Tôi sử dụng tên biến thông tin và nhận xét để hỗ trợ khả năng đọc các truy vấn lồng nhau và mã của tôi nói chung
    • Tôi kiểm tra mã của mình trước khi nó rời khỏi quyền giám hộ của tôi
1
mickmackusa