2014-01-29 14 views
0

我有一個存儲的一切副本數據庫,我們需要能夠只提取1的這個副本。該表是:PHP/MySQL的越來越每隔一行在表中的問題/停止添加記錄兩次

+----+------------+-----------+-------------+ 
| id | locationId | name  | description | 
+----+------------+-----------+-------------+ 
| 1 |   1 | rgh  | lol   | 
| 2 |   1 | rgh  | lol   | 
| 3 |   2 | tbh  | gjbh  | 
| 4 |   2 | tbh  | gjbh  | 
| 5 |   3 | lolcbj999 | abububh  | 
| 6 |   3 | lolcbj999 | abububh  | 
| 7 |   4 | test  | vhjj  | 
| 8 |   4 | test  | vhjj  | 
| 9 |   5 | ghh  | yhhh  | 
| 10 |   5 | ghh  | yhhh  | 
+----+------------+-----------+-------------+ 

我們使用%2 == 0的方法嘗試,但問題是,注意locationId是怎樣一個外鍵到這個表

+----+--------+-----------+-----------+-----------+ 
| id | walkId | longitude | latitude | timestamp | 
+----+--------+-----------+-----------+-----------+ 
| 1 |  1 | -4.067431 | 52.416904 |   2 | 
| 2 |  2 | -4.067398 | 52.416908 |   0 | 
| 3 |  3 | -4.067419 | 52.416904 |   3 | 
| 4 |  4 | -4.067482 | 52.416897 |   1 | 
| 5 |  5 | -4.067458 | 52.416897 |   1 | 
+----+--------+-----------+-----------+-----------+ 

我們希望在顯示此內容一個XML文件,那麼我們該怎麼做呢?基於事實。我們似乎無法理解這一點,我們可以返回所有賠率,所以wlak id 1,3,5但是錯過2和4,反之亦然。有任何想法嗎?

我們寧願它,如果有一種方法來阻止如果這樣使用這個數據庫,PHP代碼做什麼,我們需要改變被添加兩次記錄:

<?php 
/** 
* This file contains database related functions. 
* 
* @file 
*/ 

# prevent users from accessing this page via their browser 
if (!defined('ENTRYPOINT')) { 
    die('This is not a valid entry point.'); 
} 

require dirname(__FILE__) . '/../config.php'; 
/** 
* This function runs the query that will attempt to create the correct tables 
* in the database. 
* 
* @return a string detailing errors encountered, or FALSE if the query worked. 
*/ 
function createDatabase() { 
    $db = openConnection(); 

    $sql = <<<'SQL' 
    CREATE TABLE tbl_routes (
    id int NOT NULL AUTO_INCREMENT, title varchar(255), shortDesc varchar(255), longDesc varchar(255), 
    hours float(12), distance float(12), PRIMARY KEY (id)); 
    CREATE TABLE tbl_locations (
    id int NOT NULL AUTO_INCREMENT, walkId int NOT NULL, latitude float(12), longitude float(12), timestamp float(12), 
    PRIMARY KEY (id), FOREIGN KEY (walkId) REFERENCES tbl_routes(id)); 
    CREATE TABLE tbl_places (
    id int NOT NULL AUTO_INCREMENT, locationId int NOT NULL, description varchar(255), 
    PRIMARY KEY (id), FOREIGN KEY (locationId) REFERENCES tbl_locations(id)); 
    CREATE TABLE tbl_images (
    id int NOT NULL AUTO_INCREMENT, placeId int NOT NULL, photoName varchar(255), 
    PRIMARY KEY (id), FOREIGN KEY (placeId) REFERENCES tbl_places(id)); 
SQL; 

    $query = executeSql($sql); 
    if (!is_string($query)) { 
    return FALSE; 
    } else { 
    return $query; 
    } 
} 

/** 
* This function inputs a walk into the database. 
* 
* @param a walk object, as created by the upload.php function 
* @return a string describing the error, or SUCCESS if things worked 
*/ 
function inputWalk($walk) { 
    # TODO 
    # we need to escape the inputs to proof against SQL injections 
    # see rfc 4389 2.5.2 
    $values = [ 
    "NULL", # ID is assigned by the database thanks to AUTO_INCREMENT 
    "'$walk->title'", 
    "'$walk->shortDesc'", 
    "'$walk->longDesc'", 
    "NULL", 
    "NULL" 
    ]; 

    $sql = 'INSERT INTO tbl_routes VALUES (' . implode($values, ',') . ');'; 

    $db = openConnection(); 
    $query = mysqli_query($db, $sql); 
    if (is_bool($query) && $query === TRUE) { 
    # the SQL query worked and the data is stored 
    # we need to request the data back to see what the ID has been set to 
    $walkId = mysqli_insert_id($db); 
    foreach ($walk -> locations as &$location) { 
     $query = null; 
     $values = null; 
     $values = [ 
     "NULL", # location ID 
     $walkId, 
     "'" . mysqli_real_escape_string($db, $location->latitude) . "'", 
     "'" . mysqli_real_escape_string($db, $location->longitude) . "'", 
     "'" . mysqli_real_escape_string($db, $location->timestamp) . "'" 
     ]; 
     $query = "INSERT INTO tbl_locations VALUES (" . implode($values, ',') . ");"; 
     $sql = mysqli_query($db, $query); 
     if ($sql === FALSE) { return $query; } 
     # now need to get the locationId 
     $locID = mysqli_insert_id($db); 

     foreach ($location -> descriptions as &$description) { 
     $description[0] = mysqli_real_escape_string($db, $description[0]); 
     $description[1] = mysqli_real_escape_string($db, $description[1]); 
     # TODO: BUG: doesn't actually work... 
     $sql = "INSERT INTO tbl_places VALUES (NULL, '$locID', '$description[0]', '$description[1]');"; 
     $query = mysqli_query($db, $sql); 
     if ($query === FALSE) { return mysqli_error($db); } 
     } 


     foreach ($location -> images as &$image) { 
     $query = "INSERT INTO tbl_images VALUES (NULL, $locID, '$image[0]');"; 
     mysqli_query($db, $sql); 
     } 
    } 

    # everything worked 
    return 'SUCCESS'; # TODO: make this less hackish 
    } else { 
    return $query; 
    } 

} 

/** 
* This function opens a connection to the database. 
* @return an active database connection. 
* 
* Use closeConnection() to close it again. 
*/ 
function openConnection() { 
    global $DB_ADDR, $DB_USER, $DB_PASS, $DB_NAME; 
    $db = mysqli_connect($DB_ADDR, $DB_USER, $DB_PASS, $DB_NAME); 
    if (!$db) { 
    # connection failed 
    die('Could not connect to MySQL'); 
    } 
    return $db; 
} 

/** 
* Executes an SQL statement. 
* @param the SQL to execute 
* @return the result of the action 
* 
* On success it will return a mysqli_result() object when the SQL statement is 
* a SELECT, SHOW, DESCRIBE or EXPLAIN. Other successes will return TRUE. 
* 
* Failures will return a string explaining the error. Use is_object() to 
* discern between the error string and a result. 
*/ 
function executeSql($sql) { 
    $db = openConnection(); 
    $query = mysqli_query($db, $sql); 
    if ($query === FALSE) { 
    $query = mysqli_error($db); 
    } 
    closeDatabase($db); 
    return $query; 
} 

/** 
* Closes an active database connection. 
* @param the database connection to close. 
*/ 
function closeDatabase($db) { 
    mysqli_close($db); 
} 

/** 
* Fetches the first field of the first row of a result 
* @param The result to fetch 
* @return the first field of the first row 
* @deprecated 
*/ 
function fetchID(mysqli_result $result) { 
    return $result->fetch_row()[0]; 
} 

乾杯, 克里斯。

+0

[觀察每組的問題及答案的ROWNUMBER(http://stackoverflow.com/questions/17939198/row-number-per-group-in-mysql),你可以把一個子查詢,只有選擇rownumber = 1變體。 – Wrikken

+0

按照locationId,名稱和說明進行分組。把每一行都拉出來似乎是合乎邏輯的,但是當重複的行不相鄰時,會發生什麼?如果您有大量的行,子查詢可能會更好。您需要測試以查看哪個更快。 – Dave

+0

GROUP BY會更好,你會用子查詢重新選擇*每行*,這是非常低效的。 – MackieeE

回答

0

你可以使用group by

select min(id), locationId, name, description 
from table t 
group by locationId, name, description; 

這也許不是一個大表,這樣效率更高。相反,你可以在table(locationId, name, description, id)創建索引,並做到:

select id, locationId, name, description 
from table t 
where not exists (select 1 
        from table t2 
        where t2.locationId = t.locationId and t2.name = t.name and 
         t2.description = t.description and t2.id < t.id 
       ); 

這將選擇從每個組中的第一和可能是相當有效的與上面提到的指數。