Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Powerful & Flexible SQL Generation — without th...

Powerful & Flexible SQL Generation — without the Hassle

PHP is almost synonymous with databases, and it has been since the early versions. Yet creating SQL queries can still be a challenging task. What's the right tool to use? ORMs often feel like overkill, and creating queries by hand can be unmaintainable. In this session, I'll show you how to use the ZendDb library to generate SQL queries — from simple selects to more complex unions, filtered deletions, and updates. You'll learn how to use the library to create flexible, secure, maintainable, and reusable queries quickly and efficiently, saving you time and effort in the long term.

Matthew Setter

November 20, 2015
Tweet

More Decks by Matthew Setter

Other Decks in Programming

Transcript

  1. What You'll Learn • Generate queries programmatically • Use Named

    & Positional Parameters • Run Hand Written SQL Queries 5
  2. function buildSql($limit = null)
 {
 $sql = "SELECT name, email

    FROM employees ";
 if ($limit) {
 $sql .= "LIMIT 1, $limit";
 }
 return $sql;
 } 9
  3. function buildSql($name = null, $limit = null)
 {
 $sql =

    "SELECT name, email FROM employees";
 
 if ($name) {
 $sql .= "WHERE 'name' LIKE '{$name}%'";
 }
 
 if ($limit) {
 $sql .= "LIMIT $limit";
 }
 
 return $sql;
 } 10
  4. function buildSql($name = null, $email = null, $limit = null)


    {
 $sql = "SELECT name, email FROM employees";
 
 if ($name) {
 $sql .= "WHERE 'name' LIKE '{$name}%'";
 }
 if ($email) {
 if (!$name) {
 $sql .= "WHERE 'name' LIKE '{$name}%'";
 } else {
 $sql .= "AND 'email' = '$email'";
 }
 }
 if ($limit) {
 $sql .= "LIMIT $limit";
 }
 
 return $sql;
 } 11
  5. How Do You Build Queries 
 Which Are • Object-Oriented

    • Flexible • Maintainable • Reusable 13
  6. What is Zend\Db\Sql "Zend\Db\Sql is a SQL abstraction layer for

    building platform specific SQL queries via an object-oriented API." - http://framework.zend.com/manual/current/en/modules/zend.db.sql.html 14
  7. Why Zend\Db\SQL • It's not an ORM • It's Easy

    to Start With • Build Flexible and Reusable Queries Programmatically • It's Light & Flexible • It Integrates with Zend Framework Components 15
  8. CREATE TABLE "super_hero" ( "id" INTEGER NOT NULL AUTO_INCREMENT, "universe_id"

    INTEGER NOT NULL, "name" VARCHAR(200) NOT NULL, "active" BOOLEAN NOT NULL DEFAULT '', CONSTRAINT "tblpk" PRIMARY KEY ("id"), CONSTRAINT "tbluniq_nameuniverse" UNIQUE ( "name", "universe_id" ), CONSTRAINT "con_universefk" FOREIGN KEY 
 REFERENCES "super_hero"("universe_id") 
 ON DELETE CASCADE 
 ON UPDATE CASCADE ); 20
  9. CREATE TABLE "universe" ( "id" INTEGER NOT NULL AUTO_INCREMENT, "name"

    VARCHAR(20) NOT NULL, CONSTRAINT "tblpk" PRIMARY KEY ("id"), CONSTRAINT "tbluniq_universe" UNIQUE ("name") ); 21
  10. use Zend\Db\Sql\Sql; use Zend\Db\Sql\Ddl; use Zend\Db\Sql\Ddl\Column; use Zend\Db\Sql\Ddl\Index; use Zend\Db\Sql\Ddl\Constraint;

    $adapter = new Zend\Db\Adapter\Adapter([ 'driver' => 'Pdo', 'dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=mydb',
 'user' => 'username',
 'password' => 'password' ]); 22
  11. $idColumn = new Column\Integer('id'); $idColumn->setOption('auto_increment', true); 
 $table = new

    Ddl\CreateTable('universe'); $table->addColumn($idColumn) ->addColumn(new Column\Varchar(
 'name', 200, false )) ->addConstraint( new Constraint\PrimaryKey(['id'], 'tblpk') ) ->addConstraint(new Constraint\UniqueKey( ['name'], 'tbluniq_universe' )); 23
  12. $idColumn = new Column\Integer('id'); $idColumn->setOption('auto_increment', true); $table = new Ddl\CreateTable('super_hero');

    $table->addColumn($idColumn) ->addColumn(new Column\Varchar('name', 200, false)) ->addColumn(new Column\Integer('universe_id')) ->addColumn(new Column\Boolean('active', false)) ->addConstraint( new Constraint\PrimaryKey(['id'], 'con_tblpk') ) ->addConstraint(new Constraint\UniqueKey( ['name', 'universe_id'], 'tbluniq_nameuniverse' )) ->addConstraint(new Constraint\ForeignKey( 'fk_universe', ['universe_id'], 'universe', ['id'], 'CASCADE', 'CASCADE' )); 24
  13. $table = new Ddl\AlterTable('super_hero'); $table->addConstraint( new Index\Index( 'name, 'idx_name', 10

    ) ); $adapter->query( $sql->buildSqlString($table), $adapter::QUERY_MODE_EXECUTE ); 28
  14. INSERT INTO super_hero (name, active, universe_id)
 VALUES ('The Incredible Hulk',

    true, 2),
 ('Spiderman', true, 2),
 ('Ironman', true, 2),
 ('Superman', true, 1),
 ('Batman', true, 1); 31
  15. UPDATE super_hero 
 SET active = false 
 WHERE universe_id

    = 2
 AND name = 'The Incredible Hulk'; 36
  16. $update = $sql->update(); $update->table('super_hero') ->set(['active' => false]) ->where->equalTo('universe_id', 2) ->and->equalTo('name',

    'The Incredible Hulk'); $statement = $sql->prepareStatementForSqlObject($update) ->execute(); 37
  17. Quick Recap • Programmatically Build DDL and DML • Methods

    and Objects Map to Underlying SQL • All Rather Intuitive 41
  18. SELECT name, active
 FROM super_hero
 ORDER BY name DESC, active

    ASC
 LIMIT 1, 20; 45 Add an Order By & Limit Clause
  19. SELECT 
 sh.name as "Hero, 
 sh.active, un.name as "Universe"


    FROM super_hero sh
 INNER JOIN universe un ON (sh.universe_id = un.id)
 WHERE un.name = 'DC'
 ORDER BY sh.name DESC, sh.active ASC
 LIMIT 1, 20; 50 Add a Join & a Where Clause
  20. $statement = $adapter->createStatement(
 "SELECT 
 us.name as "Hero", us.active, 


    un.name as "Universe"
 FROM super_hero sh
 INNER JOIN universe un ON (
 sh.universe_id = un.id
 )
 WHERE un.name = 'DC'
 ORDER BY sh.name DESC, sh.active ASC
 LIMIT 1, 20"
 ); 51
  21. $select = $sql->select(); $select->from(['sh' => 'super_hero']) ->columns(["Hero" => 'name', 'active',

    'universe_id']) ->join(
 ['un' => 'universe'], 
 'un.id = sh.universe_id', 
 ["Universe" => 'name'] )
 ->where->equals('un.name', 'DC') ->order('sh.name DESC, sh.active ASC') ->limit(20) ->offset(1); 52
  22. $statement = $adapter->createStatement(
 "SELECT 
 sh.name as "Hero, sh.active, 


    un.name as "Universe"
 FROM super_hero sh
 INNER JOIN universe un ON (sh.universe_id = un.id)
 WHERE un.name = :UniverseName
 ORDER BY sh.name DESC, sh.active ASC
 LIMIT 1, 20",
 [':UniverseName' => 'DC']
 ); 53
  23. $statement = $adapter->createStatement(
 "SELECT 
 sh.name as "Hero, sh.active, un.name

    as "Universe"
 FROM super_hero sh
 INNER JOIN universe un ON (sh.universe_id = un.id)
 WHERE un.name = ? ORDER BY sh.name DESC, sh.active ASC
 LIMIT 1, 20",
 ['DC']
 ); 54
  24. $select = $sql->select(); $select->from('super_hero') ->columns(['name', 'active', 'universe_id']) ->join(
 ['un' =>

    'universe'], 
 'un.id = u.universe_id', 
 ['name'] )
 ->where($predicate) ->order('name DESC') ->limit(20) ->offset(1); 59
  25. Final Recap • Programmatically Build DDL and DML • Run

    SQL strings • Easy to Get Started • Reasonably Intuitive 63