Skip to content

Instantly share code, notes, and snippets.

@rockymontana
Created June 29, 2012 11:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rockymontana/3017478 to your computer and use it in GitHub Desktop.
Save rockymontana/3017478 to your computer and use it in GitHub Desktop.
SQL question
--
-- Table structure for table `apartments`
--
CREATE TABLE IF NOT EXISTS `apartments` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(8) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`rooms` varchar(2) COLLATE utf8_swedish_ci NOT NULL,
`floor` int(2) NOT NULL,
`m2` int(5) NOT NULL,
`address` varchar(64) COLLATE utf8_swedish_ci NOT NULL,
`house` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`available` tinyint(1) NOT NULL,
`date_of_arrival` date DEFAULT '0000-00-00',
`rent` int(5) NOT NULL COMMENT 'monthly cost',
`description` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci AUTO_INCREMENT=6 ;
--
-- Dumping data for table `apartments`
--
INSERT INTO `apartments` (`id`, `name`, `rooms`, `floor`, `m2`, `address`, `house`, `available`, `date_of_arrival`, `rent`, `description`) VALUES
(1, '0102', '3', 1, 78, 'Kringelvägen 2B', 'Draken', 0, NULL, 5700, 'Mucket fein leilighet!!'),
(3, '0101', '3', 1, 79, 'Kringelvägen 2B', 'Draken', 0, NULL, 5700, 'En likadant lägenhet!'),
(4, '0103', '3', 2, 79, 'Kringelvägen 2B', 'Draken', 0, NULL, 5900, 'Ännu en likadant lägenhet!'),
(5, '0104', '3', 2, 79, 'Kringelvägen 2B', 'Draken', 0, NULL, 5900, 'Ännu en likadant lägenhet!');
-- --------------------------------------------------------
--
-- Table structure for table `apartment_fields`
--
CREATE TABLE IF NOT EXISTS `apartment_fields` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(128) COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=3 ;
--
-- Dumping data for table `apartment_fields`
--
INSERT INTO `apartment_fields` (`id`, `name`) VALUES
(2, 'area'),
(1, 'district');
-- --------------------------------------------------------
--
-- Table structure for table `apartment_field_data`
--
CREATE TABLE IF NOT EXISTS `apartment_field_data` (
`apartment_field_id` int(11) NOT NULL,
`apartment_id` int(11) unsigned NOT NULL,
`value` varchar(128) NOT NULL,
KEY `apartment_id` (`apartment_id`),
KEY `apartment_field_id` (`apartment_field_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `apartment_field_data`
--
INSERT INTO `apartment_field_data` (`apartment_field_id`, `apartment_id`, `value`) VALUES
(1, 1, 'Mjärden'),
(2, 1, 'Maria'),
(1, 3, 'Mjärden'),
(2, 3, 'Maria'),
(1, 4, 'Mjärden'),
(2, 4, 'Maria'),
(1, 5, 'Mjärden'),
(2, 5, 'Maria');
--
-- Constraints for dumped tables
--
--
-- Constraints for table `apartment_field_data`
--
ALTER TABLE `apartment_field_data`
ADD CONSTRAINT `apartment_field_data_ibfk_1` FOREIGN KEY (`apartment_field_id`) REFERENCES `apartment_fields` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `apartment_field_data_ibfk_2` FOREIGN KEY (`apartment_id`) REFERENCES `apartments` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@rockymontana
Copy link
Author

result:
mysql> SELECT A.*,AFD.apartment_id as apartment_id, AF.name as field_name,AFD.value FROM apartments AS A, apartment_field_data as AFD INNER JOIN apartment_fields AS AF ON AFD.apartment_field_id = AF.id WHERE apartment_id = A.id
-> ;
+----+------+-------+-------+----+-----------------+--------+-----------+-----------------+------+----------------------------+--------------+------------+---------+
| id | name | rooms | floor | m2 | address | house | available | date_of_arrival | rent | description | apartment_id | field_name | value |
+----+------+-------+-------+----+-----------------+--------+-----------+-----------------+------+----------------------------+--------------+------------+---------+
| 1 | 0102 | 3 | 1 | 78 | Kringelv�gen 2B | Draken | 0 | NULL | 5700 | Mucket fein leilighet!! | 1 | area | Maria |
| 3 | 0101 | 3 | 1 | 79 | Kringelv�gen 2B | Draken | 0 | NULL | 5700 | En likadant l�genhet! | 3 | area | Maria |
| 4 | 0103 | 3 | 2 | 79 | Kringelv�gen 2B | Draken | 0 | NULL | 5900 | �nnu en likadant l�genhet! | 4 | area | Maria |
| 5 | 0104 | 3 | 2 | 79 | Kringelv�gen 2B | Draken | 0 | NULL | 5900 | �nnu en likadant l�genhet! | 5 | area | Maria |
| 1 | 0102 | 3 | 1 | 78 | Kringelv�gen 2B | Draken | 0 | NULL | 5700 | Mucket fein leilighet!! | 1 | district | Mj�rden |
| 3 | 0101 | 3 | 1 | 79 | Kringelv�gen 2B | Draken | 0 | NULL | 5700 | En likadant l�genhet! | 3 | district | Mj�rden |
| 4 | 0103 | 3 | 2 | 79 | Kringelv�gen 2B | Draken | 0 | NULL | 5900 | �nnu en likadant l�genhet! | 4 | district | Mj�rden |
| 5 | 0104 | 3 | 2 | 79 | Kringelv�gen 2B | Draken | 0 | NULL | 5900 | �nnu en likadant l�genhet! | 5 | district | Mj�rden |
+----+------+-------+-------+----+-----------------+--------+-----------+-----------------+------+----------------------------+--------------+------------+---------+

@mosbth
Copy link

mosbth commented Jun 29, 2012

SELECT A.*,AFD.apartment_id as apartment_id, AF.name as field_name,AFD.value
FROM apartments AS A, apartment_field_data as AFD
INNER JOIN apartment_fields AS AF ON
AFD.apartment_field_id = AF.id WHERE apartment_id = A.id;

mysql> SELECT A.*,AFD.apartment_id as apartment_id, AF.name as field_name,AFD.value
-> FROM apartments AS A, apartment_field_data as AFD
-> INNER JOIN apartment_fields AS AF ON
-> AFD.apartment_field_id = AF.id WHERE apartment_id = A.id
-> ;
+----+------+-------+-------+----+----------------+--------+-----------+-----------------+------+--------------------------+--------------+------------+--------+
| id | name | rooms | floor | m2 | address | house | available | date_of_arrival | rent | description | apartment_id | field_name | value |
+----+------+-------+-------+----+----------------+--------+-----------+-----------------+------+--------------------------+--------------+------------+--------+
| 1 | 0102 | 3 | 1 | 78 | Kringelvgen 2B | Draken | 0 | NULL | 5700 | Mucket fein leilighet!! | 1 | district | Mjrden |
| 1 | 0102 | 3 | 1 | 78 | Kringelvgen 2B | Draken | 0 | NULL | 5700 | Mucket fein leilighet!! | 1 | area | Maria |
| 3 | 0101 | 3 | 1 | 79 | Kringelvgen 2B | Draken | 0 | NULL | 5700 | En likadant lgenhet! | 3 | district | Mjrden |
| 3 | 0101 | 3 | 1 | 79 | Kringelvgen 2B | Draken | 0 | NULL | 5700 | En likadant lgenhet! | 3 | area | Maria |
| 4 | 0103 | 3 | 2 | 79 | Kringelvgen 2B | Draken | 0 | NULL | 5900 | nnu en likadant lgenhet! | 4 | district | Mjrden |
| 4 | 0103 | 3 | 2 | 79 | Kringelvgen 2B | Draken | 0 | NULL | 5900 | nnu en likadant lgenhet! | 4 | area | Maria |
| 5 | 0104 | 3 | 2 | 79 | Kringelvgen 2B | Draken | 0 | NULL | 5900 | nnu en likadant lgenhet! | 5 | district | Mjrden |
| 5 | 0104 | 3 | 2 | 79 | Kringelvgen 2B | Draken | 0 | NULL | 5900 | nnu en likadant lgenhet! | 5 | area | Maria |
+----+------+-------+-------+----+----------------+--------+-----------+-----------------+------+--------------------------+--------------+------------+--------+
8 rows in set (0.00 sec)

@rockymontana
Copy link
Author

    $this->data = $this->pdo->query('SELECT * FROM apartments WHERE id = '.$id)->fetch(PDO::FETCH_ASSOC);
    $field_data = $this->pdo->query('SELECT AF.name as field_name,AFD.value FROM apartment_field_data as AFD INNER JOIN apartment_fields AS AF ON AFD.apartment_field_id = AF.id WHERE apartment_id = '.$id)->fetchAll(PDO::FETCH_ASSOC);

    foreach ($field_data as $result)
        foreach ($result as $row )
            $this->data[$result['field_name']] = $row;

    foreach($this->data as $key => $value)
        if (is_null($value)) unset($this->data[$key]);

@mosbth
Copy link

mosbth commented Jun 29, 2012

select
apartment_id,
group_concat(if(name = 'district', value, null)) as district,
group_concat(if(name = 'area', value, null)) as area
from apartment_field_data as afd
inner join apartment_fields as af
on afd.apartment_field_id = af.id
group by apartment_id;

mysql> select
-> apartment_id,
-> group_concat(if(name = 'district', value, null)) as district,
-> group_concat(if(name = 'area', value, null)) as area
-> from apartment_field_data as afd
-> inner join apartment_fields as af
-> on afd.apartment_field_id = af.id
-> group by apartment_id;
+--------------+----------+-------+
| apartment_id | district | area |
+--------------+----------+-------+
| 1 | Mjrden | Maria |
| 3 | Mjrden | Maria |
| 4 | Mjrden | Maria |
| 5 | Mjrden | Maria |
+--------------+----------+-------+
4 rows in set (0.01 sec)

@rockymontana
Copy link
Author

Kudos till lillem4n ( https://github.com/lillem4n ) för denna lösningen:

public static function get_all($q = FALSE, $start = 0, $limit = 100, $order_by = FALSE, $field_search = FALSE)
{
    $pdo = Kohana_pdo::instance();
    $data_fields = array();
    $sql         = 'SELECT apartments.*,';
    foreach ($pdo->query('SELECT id, name FROM apartment_fields ORDER BY name;') as $row)
    {
        $sql .= '(SELECT GROUP_CONCAT(value SEPARATOR \', \') FROM apartment_field_data WHERE apartment_field_id = '.$row['id'].' AND apartment_id = apartments.id ORDER BY value) AS '.Mysql::quote_identifier($row['name']).',';
        $data_fields[$row['id']] = $row['name'];
    }

    $sql  = substr($sql, 0, strlen($sql) -1);

    $sql .= ' FROM apartments LEFT JOIN apartment_field_data AS apartments_data ON apartments_data.apartment_id = apartments.id';
    $sql .= ' WHERE 1 = 1';

    if (is_string($q) || ! empty($field_search)) $sql .= ' AND (';

    if (is_string($q)) $sql .= 'apartment.name LIKE '.$pdo->quote('%'.$q.'%').' OR apartment_field_data.value LIKE '.$pdo->quote('%'.$q.'%').' OR';

    if ( ! empty($field_search))
    {
        foreach ($field_search as $field => $search_string)
        {
            if ($field_id = array_search($field, $data_fields))
            {
                $sql .= 'apartments.id IN (SELECT apartment_id FROM apartment_field_data WHERE apartment_field_id = '.$field_id.' AND value LIKE '.$pdo->quote('%'.$search_string.'%').') OR';
            }
        }
    }

    if (is_string($q) || ! empty($field_search)) $sql = substr($sql, 0, strlen($sql) - 3).')';

    $sql .= ' GROUP BY apartments.id';

    if ( ! empty($order_by))
    {
        if (is_string($order_by) && in_array($order_by, $data_fields))
            $sql .= ' ORDER BY IF(ISNULL('.Mysql::quote_identifier($order_by).'),1,0),'.Mysql::quote_identifier($order_by);
        elseif ($order_by == 'value')
            $sql .= ' ORDER BY value';
        elseif (is_array($order_by))
        {
            $order_by_set = FALSE;

            foreach ($order_by as $field => $order)
            {
                if (in_array($field, $data_fields) || $field == 'name')
                {
                    if ( ! $order_by_set)
                    {
                        $sql .= ' ORDER BY ';
                        $order_by_set = TRUE;
                    }

                    if ($field == 'name')
                        $sql .= 'name';
                    else
                        $sql .= 'IF(ISNULL('.Mysql::quote_identifier($field).'),1,0),'.Mysql::quote_identifier($field);

                    if ($order == 'ASC' || $order == 'DESC') $sql .= ' '.$order;

                    $sql .= ',';
                }
            }
            if ($order_by_set) $sql = substr($sql, 0, strlen($sql) - 1);
        }
    }

    if ($limit)
    {
        if ($start) $sql .= ' LIMIT '.$start.','.$limit;
        else        $sql .= ' LIMIT '.$limit;
    }

return $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment