2012-09-19 47 views
1

我將一個SETOF從Postgres函數返回給PHP/PDO。不幸的是,我得到了每行返回的2個副本。來自Postgres的重複記錄SELECT SETOF函數

這裏是Postgres類型:

CREATE TYPE marker AS (i BOOLEAN, r DOUBLE PRECISION, la DOUBLE PRECISION, lo DOUBLE PRECISION, n INTEGER); 

和函數:

CREATE OR REPLACE FUNCTION rl_select_markers (latitude DOUBLE PRECISION, longitude DOUBLE PRECISION) RETURNS setof marker AS $$ 
DECLARE 
ROW marker%ROWTYPE; 
BEGIN 
    FOR ROW IN SELECT is_male, rate, lat, lon, (EXTRACT(EPOCH FROM CURRENT_TIMESTAMP - created_at)/60)::INTEGER FROM markers 
    WHERE expires_at > CURRENT_TIMESTAMP 
    ORDER BY ST_Distance(ST_Point(longitude, latitude), geog, FALSE) LIMIT 25 
    LOOP 
    RETURN NEXT ROW; 
    END LOOP; 
    RETURN; 
END; 
$$ LANGUAGE plpgsql; 

下面是相關PHP:

$dbh = new PDO('pgsql:host=' . $host . ';dbname=' . $db, $user, $pw); 
$stmt = $dbh->prepare("SELECT rl_select_markers (:lat, :lon)"); 
$stmt->bindParam(':lat', $lat, PDO::PARAM_INT); 
$stmt->bindParam(':lon', $lon, PDO::PARAM_INT); 
$stmt->execute(); 

$keys = array('i', 'r', 'la', 'lo', 'n'); 
$markers = array(); 
while ($lines = $stmt->fetch()) 
{ 
    $log->logInfo($log_id . " lines=" . $lines); 
    $combined = array(); 
    foreach ($lines as $line) 
    { 
     $log->logInfo($log_id . " line=" . $line); 
     // Remove brackets around $line and put in array 
     $vals = explode(",", substr($line, 1, strlen($line)-2)); 
     // Combine into key value pairs 
     $combined = array_combine($keys, $vals); 
    } 
    $markers[] = array("m"=>$combined); 
} 

$dbh = null; 
$stmt = null; 

$log->logInfo($log_id . " Send 200 OK"); 
sendResponse(200, json_encode(array("mks"=>$markers)), "application/json"); 

意外的行爲是每個$lines是同一行的兩個副本的數組。

E.G.當有一條記錄返回時$lines將是一個2個完全相同的字符串的數組。所以上述記錄將產生:

lines=Array 
line=(f,10,51.505601,-0.109917,8) 
line=(f,10,51.505601,-0.109917,8) 

我明白我內心的PHP循環是無稽之談,但它的工作原理。我可以看到解決方法(如添加一個break;),但想要刪除重複。

我希望我已經解釋清楚。你能看到爲什麼我得到這些每個記錄的重複?

編輯

繼@ a_horse_with_no_name的評論的問題:

調用從phpPgAdmin的在SQL或功能並沒有產生重複。

+2

不要在SQL客戶端像PSQL運行查詢時,(你會看到這些重複也即在PHP之外)。 –

+0

在你的函數中,寂寞的'RETURN;'是不必要的。不是說這對你來說是一種解決方案... – dezso

+0

@a_horse_with_no_name:當我在phpPgAdmin中運行SQL時,我沒有得到重複。 – Polly

回答

1

我認爲你犯了一個錯誤,認爲fetch()函數會返回多行 - 它總是返回一行 - 一列數組。

作爲默認$fetch_stylePDO::FETCH_BOTH此陣列上兩列名和0索引的列號索引,並且具有用於每列的兩個元件:

0 => (f,10,51.505601,-0.109917,8) 
'rl_select_markers' => (f,10,51.505601,-0.109917,8) 

所以:

  • 使用取(PDO :: FETCH_NUM),所以你會得到一個數字索引列;
  • 擺脫foreach ($lines as $line)
  • 重命名變量$lines$line
  • 只使用$line[0]

更正代碼:

while ($line = $stmt->fetch(PDO::FETCH_NUM)) 
{ 
    $log->logInfo($log_id . " line=" . print_r($line,TRUE)); 
    $combined = array(); 
    // Remove brackets around $line and put in array 
    $vals = explode(",", substr($line[0], 1, strlen($line[0])-2)); 
    // Combine into key value pairs 
    $combined = array_combine($keys, $vals); 
    $markers[] = array("m"=>$combined); 
} 

PHP GOTHA上午十時正64372

更妙的是:我會用select (rl_select_markers (:lat, :lon)).*查詢,然後只是:

while ($combined = $stmt->fetch(PDO::FETCH_ASSOC)) { 
    $markers[] = array("m"=>$combined); 
} 
+0

我非常驚訝'fetch'返回了一個數組。當然,我可以抓住第一個索引,但這仍然涉及PDO抓取重複項(我忽略它們)。哪個不理想。 – Polly

+0

我不會馬上理解你的改進代碼。快速搜索'PHP GOTHA Nr 64372'找不到任何東西。今天下午有一段時間我會進一步調查你的代碼。謝謝。 – Polly

+0

這個_PHP GOTHA Nr 64372_是個玩笑,你知道。關於多麼可怕的PHP是。 – Tometzky