Как вы встроили свои sql-запросы в php-скрипты (стиль кодирования)?

как вы встраиваете свои sql-скрипты в php? Вы просто пишете их в строке или heredoc или передаете их в файл sql? Существуют ли какие-либо рекомендации, когда их можно передать на аутсорсинг? Есть ли элегантный способ организовать это?

Ответ 1

Используйте фреймворк с уровнем ORM (Object-Relational Mapping). Таким образом, вам не нужно размещать прямой SQL в любом месте. Встроенный SQL отстой для удобочитаемости, обслуживания и всего.

Ответ 2

Всегда помните, чтобы избежать ввода. Не делайте это вручную, используйте подготовленные заявления. Вот пример метода из моего класса отчетов.

public function getTasksReport($rmId, $stage, $mmcName) {
    $rmCondition = $rmId ? 'mud.manager_id = :rmId' : 'TRUE';
    $stageCondition = $stage ? 't.stage_id = :stageId' : 'TRUE';
    $mmcCondition = $mmcName ? 'mmcs.username = :mmcName' : 'TRUE';
    $sql = "
            SELECT
                    mmcs.id AS mmc_id,
                    mmcs.username AS mmcname,
                    mud.band_name AS mmc_name,
                    t.id AS task_id,
                    t.name AS task, 
                    t.stage_id AS stage,
                    t.role_id,
                    tl.id AS task_log_id,
                    mr.role,
                    u.id AS user_id,
                    u.username AS username,
                    COALESCE(cud.full_name, bud.band_name) AS user_name,
                    DATE_FORMAT(tl.completed_on, '%d-%m-%Y %T') AS completed_on,
                    tl.url AS url,
                    mud.manager_id AS rm_id
            FROM users AS mmcs
            INNER JOIN banduserdetails AS mud ON mud.user_id = mmcs.id
            LEFT JOIN tasks AS t ON 1
            LEFT JOIN task_log AS tl ON tl.task_id = t.id AND tl.mmc_id = mmcs.id
            LEFT JOIN mmc_roles AS mr ON mr.id = t.role_id
            LEFT JOIN users AS u ON u.id = tl.user_id
            LEFT JOIN communityuserdetails AS cud ON cud.user_id = u.id
            LEFT JOIN banduserdetails AS bud ON bud.user_id = u.id
            WHERE mmcs.user_type = 'mmc'
                    AND $rmCondition
                    AND $stageCondition
                    AND $mmcCondition
            ORDER BY mmcs.id, t.stage_id, t.role_id, t.task_order
    ";
    $pdo = new PDO(.....);
    $stmt = $pdo->prepare($sql);
    $rmId and $stmt->bindValue('rmId', $rmId); // (1)
    $stage and $stmt->bindValue('stageId', $stage); // (2)
    $mmcName and $stmt->bindValue('mmcName', $mmcName); // (3)
    $stmt->execute();
    return $stmt->fetchAll();
}

В строках, обозначенных (1), (2) и (3), вы увидите способ условной привязки.

Для простых запросов я использую структуру ORM, чтобы уменьшить необходимость создания SQL вручную.

Ответ 3

Это зависит от размера и сложности запроса.

Мне лично нравится heredocs. Но я не использую его для простых запросов. Это не важно. Главное "Никогда не забывайте избегать значений"

Ответ 4

Вы всегда должны действительно действительно ВСЕГДА использовать инструкции подготовки с держателями мест для своих переменных.

Его немного больше кода, но он работает более эффективно на большинстве БД и защищает вас от атак SQL-инъекций.

Ответ 5

Я предпочитаю как таковой:

$sql = "SELECT tbl1.col1, tbl1.col2, tbl2.col1, tbl2.col2"
        . " FROM Table1 tbl1"
        . " INNER JOIN Table2 tbl2 ON tbl1.id = tbl2.other_id"
        . " WHERE tbl2.id = ?"
        . " ORDER BY tbl2.col1, tbl2.col2"
        . " LIMIT 10, 0";

Может потребоваться немного времени на PHP, чтобы объединить все строки, но я думаю, что это выглядит намного приятнее и легче редактировать.

Конечно, для чрезвычайно длинных и специализированных запросов было бы целесообразно прочитать файл .sql или использовать хранимую процедуру. В зависимости от вашей структуры это может быть просто:

$sql = (string) View::factory('sql/myfile');

(дает вам возможность назначать переменные в представлении/шаблоне, если необходимо). Без помощи механизма шаблонов или фреймворка вы должны использовать:

$sql = file_get_contents("myfile.sql");

Надеюсь, что это поможет.

Ответ 6

Я обычно пишу их как аргумент функции:

db_exec ("SELECT ...");

За исключением случаев, когда sql будет очень большим, я передаю его как переменную:

$SQL = "SELECT ...";
$result = db_exec ($SQL);

(Я использую функции-обертки или объекты для операций с базой данных)

Ответ 7

$sql = sprintf("SELECT * FROM users WHERE id = %d", mysql_real_escape_string($_GET["id"]));

Безопасный запуск MySQL

Ответ 8

Вы можете использовать ORM или построитель строк sql, но некоторые сложные запросы требуют написания sql. При написании sql, как показывает Michał Słaby, используйте привязки запросов. Связывание запросов предотвращает внедрение sql и поддерживает читаемость. Что касается того, где поставить ваши запросы: использовать классы моделей.

Ответ 9

Как только вы доберетесь до определенного уровня, вы поймете, что 99% написанного SQL могут быть автоматизированы. Если вы пишете столько запросов, которые вы думаете о файле свойств, вы, вероятно, делаете то, что может быть проще:

Большая часть материала, который мы программисты, это CRUD: Create Read Update Delete

В качестве инструмента для себя я создал Pork.dbObject. Объектная привязка Mapper + Active Запись в 2 простых классах (класс абстракции базы данных + класс dbObject)

Несколько примеров из моего сайта:

Создать веб-журнал:   

    $weblog = new Weblog(); // create an empty object to work with. 
    $weblog->Author = 'SchizoDuckie'; // mapped internally to strAuthor. 
    $weblog->Title = 'A test weblog';  
    $weblog->Story = 'This is a test weblog!'; 
    $weblog->Posted = date("Y-m-d H:i:s"); 
    $weblog->Save(); // Checks for any changed values and inserts or updates into DB. 
    echo ($weblog->ID) // outputs: 1 

И один ответ на него:   

    $reply = new Reply(); 
    $reply->Author = 'Some random guy'; 
    $reply->Reply = 'w000t'; 
    $reply->Posted = date("Y-m-d H:i:s"); 
    $reply->IP = '127.0.0.1'; 
    $reply->Connect($weblog); // auto-saves $reply and connects it to $weblog->ID 

И, выборка и отображение веб-журнала + все ответы:   

    $weblog = new Weblog(1); //Fetches the row with primary key 1 from table weblogs and hooks it values into $weblog;

    echo("<h1>{$weblog->Title}</h1> 
    <h3>Posted by {$weblog->Author} @ {$weblog->Posted}</h3> 
    <div class='weblogpost'>{$weblog->Story}</div>"); 

    // now fetch the connected posts. this is the real magic: 
    $replies = $weblog->Find("Reply"); // fetches a pre-filled array of Reply objects. 
    if ($replies != false) 
    { 
        foreach($replies as $reply) 
        { 
            echo("<div class='weblogreply'><h4>By {$reply->Author} @ {$reply->Posted}</h4> {$reply->Reply}</div>"); 
        } 
    } 

Объект weblog будет выглядеть так:   

class Weblog extends dbObject 
{ 
    function __construct($ID=false) 
    { 
        $this->__setupDatabase('blogs', // database table 
        array('ID_Blog' => 'ID',    // database field => mapped object property 
            'strPost' => 'Story',    // as you can see, database field strPost is mapped to $this->Story 
            'datPosted' => 'Posted', 
            'strPoster' => 'Author', 
            'strTitle'  => 'Title',
            'ipAddress'  => 'IpAddress', 
            'ID_Blog',    // primary table key  
            $ID);    // value of primary key to init with (can be false for new empty object / row) 
        $this->addRelation('Reaction'); // define a 1:many relation to Reaction 

    }
}

Смотрите, никаких ручных SQL-писем:) Ссылка + еще примеры: Pork.dbObject

О да, я также создал рудиментарный графический интерфейс для моего инструмента для строительных лесов: Pork.Generator

Ответ 10

Мне нравится этот формат. Это было упомянуто в предыдущем комментарии, но выравнивание показалось мне.

$query = "SELECT "
       . " foo, "
       . " bar "
       . "FROM "
       . " mytable "
       . "WHERE "
       . " id = $userid";

Достаточно легко читать и понимать. Точки выстраиваются в линию с помощью знака равенства, сохраняя все в чистой строке.

Мне нравится идея держать ваш SQL в отдельном файле, хотя я не уверен, как это работает с переменными типа $userid в моем примере выше.