How do you manage SQL Queries

后端 未结 10 1701
深忆病人
深忆病人 2020-12-13 05:59

At the moment my code (PHP) has too many SQL queries in it. eg...

// not a real example, but you get the idea...
$results = $db->GetResults(\"SELECT * FRO         


        
相关标签:
10条回答
  • 2020-12-13 06:18

    I had to clean up a project wich many (duplicate/similar) queries riddled with injection vulnerabilities. The first steps I took were using placeholders and label every query with the object/method and source-line the query was created. (Insert the PHP-constants METHOD and LINE into a SQL comment-line)

    It looked something like this:

    -- @Line:151 UserClass::getuser():

    SELECT * FROM USERS;
    

    Logging all queries for a short time supplied me with some starting points on which queries to merge. (And where!)

    0 讨论(0)
  • 2020-12-13 06:20

    There are some libraries, such as MDB2 in PEAR that make querying a bit easier and safer.

    Unfortunately, they can be a bit wordy to set up, and you sometimes have to pass them the same info twice. I've used MDB2 in a couple of projects, and I tended to write a thin veneer around it, especially for specifying the types of fields. I generally make an object that knows about a particular table and its columns, and then a helper function in that fills in field types for me when I call an MDB2 query function.

    For instance:

    function MakeTableTypes($TableName, $FieldNames)
    {
        $Types = array();
    
        foreach ($FieldNames as $FieldName => $FieldValue)
        {
            $Types[] = $this->Tables[$TableName]['schema'][$FieldName]['type'];
        }
    
        return $Types;
    }
    

    Obviously this object has a map of table names -> schemas that it knows about, and just extracts the types of the fields you specify, and returns an matching type array suitable for use with an MDB2 query.

    MDB2 (and similar libraries) then handle the parameter substitution for you, so for update/insert queries, you just build a hash/map from column name to value, and use the 'autoExecute' functions to build and execute the relevant query.

    For example:

    function UpdateArticle($Article)
    {
        $Types = $this->MakeTableTypes($table_name, $Article);
    
        $res = $this->MDB2->extended->autoExecute($table_name,
            $Article,
            MDB2_AUTOQUERY_UPDATE,
            'id = '.$this->MDB2->quote($Article['id'], 'integer'),
            $Types);
    }
    

    and MDB2 will build the query, escaping everything properly, etc.

    I'd recommend measuring performance with MDB2 though, as it pulls in a fair bit of code that might cause you problems if you're not running a PHP accelerator.

    As I say, the setup overhead seems daunting at first, but once it's done the queries can be simpler/more symbolic to write and (especially) modify. I think MDB2 should know a bit more about your schema, which would simpify some of the commonly used API calls, but you can reduce the annoyance of this by encapsulating the schema yourself, as I mentioned above, and providing simple accessor functions that generate the arrays MDB2 needs to perform these queries.

    Of course you can just do flat SQL queries as a string using the query() function if you want, so you're not forced to switch over to the full 'MDB2 way' - you can try it out piecemeal, and see if you hate it or not.

    0 讨论(0)
  • 2020-12-13 06:20

    I try to use fairly generic functions and just pass the differences in them. This way you only have one function to handle most of your database SELECT's. Obviously you can create another function to handle all your INSERTS.

    eg.

    function getFromDB($table, $wherefield=null, $whereval=null, $orderby=null) {
        if($wherefield != null) { 
            $q = "SELECT * FROM $table WHERE $wherefield = '$whereval'"; 
        } else { 
            $q = "SELECT * FROM $table";
        }
        if($orderby != null) { 
            $q .= " ORDER BY ".$orderby; 
        }
    
        $result = mysql_query($q)) or die("ERROR: ".mysql_error());
        while($row = mysql_fetch_assoc($result)) {
            $records[] = $row;
        }
        return $records;
    }
    

    This is just off the top of my head, but you get the idea. To use it just pass the function the necessary parameters:

    eg.

    $blogposts = getFromDB('myblog', 'author', 'Lewis', 'date DESC');
    

    In this case $blogposts will be an array of arrays which represent each row of the table. Then you can just use a foreach or refer to the array directly:

    echo $blogposts[0]['title'];
    
    0 讨论(0)
  • 2020-12-13 06:22

    I'd move all the SQL to a separate Perl module (.pm) Many queries could reuse the same functions, with slightly different parameters.

    A common mistake for developers is to dive into ORM libraries, parametrized queries and stored procedures. We then work for months in a row to make the code "better", but it's only "better" in a development kind of way. You're not making any new features!

    Use complexity in your code only to address customer needs.

    0 讨论(0)
提交回复
热议问题