これは、私がこれまでに聞いた中で最も馬鹿げた質問の1つであるに違いありませんが、SQLスクリプトの中に、実行をブロックしている何か本当にひどい問題があるはずです。
次のサンプルCLI構文を使用してcobertura.sqlファイルを呼び出しています。
psql -h localhost -U myUser -f cobertura.sql myDB
ただし、次のエラーが表示されます。
psql:cobertura.sql:29: ERROR: "sql " is not a known variable LINE 14: sql := format('insert into cobertura_tmp select count(*) as ... cobertura.sql file:
DO language plpgsql $$
declare
eq record;
sql varchar;
BEGIN
create table if not exists cobertura_tmp (num integer, realtime char(1), lat numeric, lng numeric);
truncate table cobertura_tmp;
for eq in select imei_equipo as imei from cliente_avl_equipo where id_cliente in (select id from cliente where nombre ilike '%enangab%') limit 3
loop
sql := format('insert into cobertura_tmp select count(*) as num, tipo as realtime, round(CAST(latitud as numeric), 4) as lat ,round(CAST(longitud as numeric), 4) as lng from reports.avl_historico_%s where latitud between -38.67405472 and -36.75131149 and longitud between -73.08429161 and -69.65333954 group by tipo, round(CAST(latitud as numeric), 4),round(CAST(longitud as numeric), 4)', eq.imei);
execute sql;
end loop;
update cobertura_tmp set num= -1* num where realtime='S';
create table if not exists cobertura_tmp_resumen (num integer, lat numeric, lng numeric);
truncate cobertura_tmp_resumen;
-- select sum(num) as num , lat, lng into cobertura_tmp_resumen from cobertura_tmp group by lat,lng;
-- drop table if exists cobertura_tmp;
END;
$$;
同じスクリプトは、Posticoバージョン1.3.2(2318)を使用してMac OSXからリモートでスムーズに実行されます。
質問:sql
セクションにあるdeclare
変数を見つけないのはなぜですか?
あなたのエラーメッセージは言う:
_psql:cobertura.sql:29: ERROR: "sql " is not a known variable LINE 14: sql := format('insert into cobertura_tmp select count(*) as ...
_
よく見て:_"sql "
_、_"sql"
_ではない
つまり、無害なスペース文字の代わりに、 "sql"の直後に卑劣で目に見えない文字があるということです。それはあなたの質問にはありません、あなたがここであなたの質問にそれをコピーして貼り付けたときにおそらく翻訳で失われました。元のコードには次のようなものが含まれています。
_sql := format ...
_
あなた見えますか?番号? seeできないからです。 (この特定のケースでは、スペースが少し広いことに気付くかもしれません-お使いのブラウザー、フォント、文字セットが私のものと同じ結果を生成する場合。)"ideographic space"、Unicode _U+3000
_、HTML _ 
_。単なるランダムな例です。 Unicodeにはそのようなさまざまな文字があります。単純なスペースに置き換えて、問題を解決してください。
dbfiddle ここ
nicodeについてこれは嫌いです。文字が多すぎて、ほとんどの場合人々を混乱させるだけです...
簡単なテスト:
_SELECT ascii(' '); -- 32 -- plain space
SELECT ascii(' '); -- 12288 -- not a plain space
SELECT ' ' = ' '; -- f -- not the same!
_
文字列にany非ASCII文字があるかどうかの簡単なテスト:
_SELECT octet_length(string) = char_length(string) -- f
FROM (SELECT text 'sql := format' AS string) t;
_
エンコードUTF8を想定すると、非ASCII文字は2〜4バイトを占有しますが、単純なASCII文字は1バイトを占有します。 octet_length()
は
文字列のバイト数
一方、char_length()
(length()
と同じ)は文字の数を返します。すべてASCIIの場合、どちらも同じ結果を返します。 octet_length()
がより大きな数値を返す場合は、不審な文字があります。何も意味する必要はありません。文字列内のアクセント記号付きの文字は、その文字に適しています。
または、容疑者を強調表示できるエディターを使用します。
脇、それをしている間、あなたのplpgsqlコードは次のようにかなり効率的になります:
_DO
$$
DECLARE
_imei text;
_sql text;
BEGIN
IF to_regclass('pg_temp.cobertura_tmp') IS NULL -- if tmp table does not exist
THEN
CREATE TABLE cobertura_tmp (
num integer
, realtime char(1)
, lat numeric
, lng numeric
);
ELSE
TRUNCATE TABLE cobertura_tmp;
END IF;
FOR _imei IN
SELECT e.imei_equipo::text -- imei is NOT NULL & *safe* against SQL injection
FROM cliente c
JOIN cliente_avl_equipo e ON e.id_cliente = c.id -- assuming c.id is UNIQUE
WHERE c.nombre ILIKE '%enangab%'
LIMIT 3
LOOP
_sql := format(
$s$
INSERT INTO cobertura_tmp (num, realtime, lat, lng)
SELECT count(*)::int * (CASE WHEN a.tipo = 'S' THEN -1 ELSE 1 END) -- AS num
, a.tipo -- AS realtime
, round(a.latitud::numeric, 4) -- AS lat
, round(a.longitud::numeric, 4) -- AS lon
FROM reports.avl_historico_%s a
WHERE a.latitud BETWEEN -38.67405472 AND -36.75131149
AND a.longitud BETWEEN -73.08429161 AND -69.65333954
GROUP BY 2,3,4
$s$
, _imei);
EXECUTE _sql;
END LOOP;
/* integrated above to avoid costly extra update:
UPDATE cobertura_tmp
SET num = -1 * num
WHERE realtime = 'S';
*/
-- ... etc
END
$$;
_
詳細はたくさんありますが、それは質問のトピックではありませんです。私はあなたが一時テーブルをまったく必要としないと思います...
コードを改善したい場合は、試してください。関連: