簡體   English   中英

如何基於INNER JOIN SQL查詢或php中的一張表來限制頁面結果的數量?

[英]How to limit the number of page results based on one table in INNER JOIN SQL query or in php?

我正在嘗試每頁包含答案的問題5個(問題和答案表一對一的關系),但是,我正在獲得此聯接表每頁的記錄數,無論如何,是否有限制基於問題表的結果分頁。

<?php
$topic_id = $_GET['topic_id'];
$answers_data = [];
$questions_data = [];
if (isset($_GET["page"])) { $page  = $_GET["page"]; } else { $page=1; }; 
$num_rec_from_page = 5;
$start_from = ($page-1) * $num_rec_per_page;
$sql = "SELECT questions.q_id,questions.question,answers.answers,answers.answer_id FROM questions INNER JOIN answers ON questions.q_id = answers.q_id WHERE topic_id='$topic_id' LIMIT $start_from, $num_rec_from_page";
$result = $connection->query($sql);
while($row = mysqli_fetch_assoc($result)) {
$data[] = $row;
}//While loop

foreach($data as $key => $item) {
    $answers_data[$item['q_id']][$item['answer_id']] = $item['answers'];
}
foreach($data as $key => $item) {
    $questions_data[$item['q_id']] = $item['question'];
}
?>

我使用以下2個for-each循環獲取上述查詢數據的結果。

<?php
$question_count= 0;
foreach ($answers_data as $question_id => $answers_array) {
$question_count++;
$q_above_class = "<div class='uk-card-default uk-margin-bottom'><div class='uk-padding-small'><span class='uk-article-meta'>Question :".$question_count."</span><p>";
$q_below_class = "</p></span><div class='uk-padding-small'>";

echo $q_above_class.$questions_data[$question_id].$q_below_class;

$answer_count = 0;
foreach($answers_array as $key => $answer_options) {
$answer_count++;
$answer_options = strip_tags($answer_options, '<img>');
$ans_above_class="<a class='ansck'><p class='bdr_lite uk-padding-small'><span class='circle'>".$answer_count."</span>";
$ans_below_class = "</p></a>";
  echo $ans_above_class.$answer_options.$ans_below_class; 
}
echo "</div></div></div>";   
}
?>

有什么想法,我如何限制基於問題表的每頁結果。

像這樣的東西

SELECT
    q.q_id,
    q.question,
    a.answers,
    a.answer_id
FROM
    (
        SELECT
            q_id, question
        FROM
            questions
        WHERE
            topic_id=:topic_id           
        LIMIT
            $start_from, $num_rec_from_page
    ) AS q
JOIN
    answers AS a ON q.q_id = a.question_id

一些問題/想法/筆記。

  • 您有question.q_idquestion.question_id ,這似乎是一個錯誤。 所以我只用了q_id ,另一個是更多的打字(我不喜歡),我有50-50的機率……

  • 您只有topic_id所以我不確定它來自哪個表,我假設它來自表“ question”? 差異很大,因為我們確實需要子查詢的where條件限制在哪里。

  • 內部聯接與聯接是同一回事,所以我放聯接是因為我很懶。 我在SO上找到了上一篇有關它的文章( 請單擊此處

  • :topic_id我參數化了您的查詢,但不進行變量串聯和SQLInjection漏洞之類的工作。 (又名,請使用准備好的語句 )命名占位符用於PDO,這就是我喜歡使用的占位符,您幾乎可以將其替換為? 對於mysqli

  • 就像我對INNER JOIN所說的那樣,我很懶,所以我喜歡只用1個字符來別名表,這就是我所做的。 (我認為您甚至不需要AS部分,但我並不“懶”)。 有時我必須使用2,這確實讓我感到惱火,但無論如何

使用子查詢,您可以只限制該表中的行,然后像平常一樣將查詢的結果連接回主查詢。 這樣,您從問題表中拉出5或有什么,然后僅基於對內部查詢結果的聯接而從答案中提取{n}行。

不能真正測試它,但是從理論上講它應該可以工作。 您必須仔細檢查結果,然后按問題分組。 因為您將獲得{n}行,其中包含相同的5問題。 使用PDO,您可以執行PDO::FETCH_GROUP我認為Mysqli沒有等效的方法,因此您必須手動進行操作,但這非常簡單。

更新

這是我收集的數據庫小提琴,您可以看到它完全滿足您的需要

https://www.db-fiddle.com/f/393uFotgJVPYxVgdF2Gy2V/3

另外,我在其下放置了一個非子查詢以顯示差異。

至於小語法錯誤和表/列名之類的問題,那么我無權訪問您的數據庫,您將不得不付出一些努力以使其適應您的設置。 我僅有的信息是您在問題中輸入的內容,因此您的問題的表/列名稱錯誤。 我之前已經指出了其中一些問題。 我並不是說刻薄或屈尊,這只是一個直白的事實。

更新1

根據您的評論。 in 1st query the question is redundant

這只是數據庫的工作方式,要說明這一點非常簡單,在我的示例中,我有5個問題與8個答案相匹配。 在任何數據庫(不包括像mongoDB這樣的NoSQL)中,您都無法實際嵌套數據。 換句話說,您不能像這樣拉它。

  question1
      answer1
      answer2
      answer3

您必須將其拉平,發生的方式是這樣的

  question1 answer1
  question1 answer2
  question1 answer3

這只是數據庫在連接數據時如何工作的自然結果。 既然這已經不可行了,我們將如何處理。 因為我們希望像第一個示例一樣嵌套數據。

  1. 我們可以拉出問題,對結果進行迭代(循環),並對每個問題進行查詢,然后將數據添加到子元素中。
    • 優勢這很容易做到
    • 缺點盡管這樣做是不希望的,因為我們將與數據庫建立6個連接(1個連接5個問題,1個連接5個問題的每一個) ,它需要2個while循環來處理結果,實際上需要更多的代碼。

偽代碼指令(我不喜歡編碼)

       init data variable
       query for our 5 questions
       while each questions as question
           - add question to data
           - query for answers that belong to question
           - while each answers as answer
               -- add answer to nested array in data[question]
       return data
  1. 我們可以處理結果並構建所需的結構。
    • 優勢我們可以拉一個請求的數據
    • 缺點是我們必須在#1中編寫一些代碼。 我們仍然必須編寫代碼,並且實際上我們必須編寫更多的代碼,因為我們必須將數據庫結果處理6x(2 while循環),這里我們需要1 while循環。

偽代碼指令(用於比較)

       init data variable
       query for our 5 questions and their answers
       while each questions&answers as row
           - check if question is in data
             -- if no, add question with a key we can match to it
           - remove data specific to question (redundant data)
           - add answers to data[question]
       return data

如您所見,第二條的基本說明並不比第一條復雜(相同數量的指令)。 這只是假設每行具有相同的復雜性。 顯然,與if條件相比,SQL查詢或while循環更復雜。 您將在下面看到我如何將此偽代碼轉換為真實代碼。 實際上,我在計划項目時經常寫psudo代碼。

無論如何,這是我們需要做的。 (使用先前的SQL或小提琴中的第一個)。 這是從數據庫中提取數據的常規“標准”循環

 $data = [];
 while($row = mysqli_fetch_assoc($result)) {
     $data[] = $row;
 }//While loop

我們將對此進行一點修改(非常簡單)

//query for our 5 questions and their answers(using SQL explained above)
//init data variable
$data = [];
//while each questions&answers as row
while($row = mysqli_fetch_assoc($result)) {
   // - create a key based of the question id, for convenience
   $key = 'question_'.$row['q_id'];
   // - check if question is in data
   if(!isset( $data[$key] ) ){
       //--if no, add question with a key we can match to it
       $data[$key] = [
            'q_id' => $row['q_id'],
            'question' => $row['question'],
            'children' => []  //you can call this whatever you want, i choose "children" because there is a field named "answers"
       ];
   }
   //- remove data specific to question (redundant data) [optional]
   unset($data['q_id'], $data['question']);
   //- add answers to data[question]
   $data[$key]['answers'][] = $row;
}
//return data

所以這是什么樣子:在第一個標准時間里,我們將其稱為冗余數據。

[
    ["q_id" => "4", "question" => "four", "answers"=>"4", "answer_id"=>"4"],
    ["q_id" => "5", "question" => "five", "answers"=>"5", "answer_id"=>"5"],
    ["q_id" => "5", "question" => "five", "answers"=>"5", "answer_id"=>"6"],
]

對於第二個,通過更難的代碼(不是很困難),我們得到了:

[
    ["q_id" => "4","question" => "four","children" = ["answers"=>"4","answer_id"=>"4"]],
    [
        "q_id" => "5",
        "question" => "five",
        "children" = [
            "answers"=>"5",
            "answer_id"=>"5"
        ],[
            "answers"=>"5",
            "answer_id"=>"6"
        ]
    ],
]

我擴展了第二個問題,以便您可以看到嵌套。 這也是為什么它具有冗余數據以及一般情況的一個很好的例子。 如您所見,如果沒有一些冗余數據(不嵌套它們),就無法用5個共享問題來表示8行。

我最后要提到的是我選擇的$key 我們本可以僅使用q_id ,而無需添加question_位。 我這樣做有兩個原因。

  1. 打印出來時更容易閱讀。
  2. PHP中有幾個array_* (和其他)函數將重置數字鍵。 因為我們在這里存儲重要數據,所以我們不想丟失這些信息。 做到這一點的方法是使用字符串。 您可以將其(int)$row['q_id']轉換為字符串(int)$row['q_id'] ,但是在某些情況下,鍵仍然可以刪除。 例如,當使用JSON編碼時,有一個標志JSON_FORCE_OBJECT強制數字鍵成為對象{"0":"value}但它的作用是全局的。在任何情況下,如果它們只是數字,則可能會丟失鍵,我對此不太在意,所以我給它們加了前綴以防止發生這種情況。
  3. preg_match('/question_([0-9]+)/', $key, $match)$id = substr($key, 9);這樣的事情並不難$id = substr($key, 9); 把它拉回去,我們在數組中有q_id ,檢查isset($data['question_1'])然后再檢查isset($data['1'])並不困難,它看起來更好。

因此,為了最小的困難,我們可以確定我們不會將ID丟失到站點上的某些代碼中(除非我們使用usort而不是uasort ),但是我離題了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM