I am using an MVC framework (Zend) for my application and I want to find the total size of a table in PostgreSQL (including index). The table name is "V5TableName" - quotes included because table name is case sensitive. I have made sure that there is NO typo involved.
My code to get the table size is shown below:
public function getMyTableSize()
{
$sql = "SELECT pg_size_pretty(pg_total_relation_size( '\"V5TableName\"' ) );";
/* Custom_Db is a custom library in my application which makes the PostgreSQL connection
and queries the database
*/
$tableSize = Custom_Db::query($sql)->fetchColumn();
return $tableSize;
}
When my application calls this function it returns the following error in my logs :
[22-Apr-2020 09:42:37] PID:30849 ERR: SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "V5TableName" does not exist
LINE 1: SELECT pg_size_pretty(pg_total_relation_size( '"V5TableName...
^
query was: SELECT pg_size_pretty(pg_total_relation_size( '"V5TableName"' ) );
If I run this same query in pgAdmin4 it works perfectly fine returning the table size (for instance: 104Mb).
I have tried:
Removing and adding quotes to the table name in the code.
Appending the schema as prefix to the table name (example: 'public."V5TableName"').
NONE of the above seem to work. I am not sure what is going wrong over here.
I also tried to find the total database size in my application (db name: MyDbName - with mixed case spelling) and my query looked something like below:
$sql = "SELECT pg_size_pretty(pg_database_size('MyDbName'))"; // this DID NOT WORK
So I changed it to the one shown below: (it worked)
$sql = "SELECT pg_size_pretty(pg_database_size( current_database() ))"; // this WORKED
I was wondering if there is something similar that could be done to find the table size.
Your query should work. The use of double-quotes seems correct.
SELECT pg_size_pretty(pg_total_relation_size('"V5TableName"'));
First make sure you are connecting to the right database cluster (a.k.a. "server"). It's defined by its data directory, or equally unambiguous by hostname and port number. Read the manual here and here.
Then make sure you are connecting to the right database within that database cluster. A Postgres database cluster consists of 1-n databases. When connecting without specifying the actual database, you end up in the maintenance database named postgres by default. That's the most likely explanation. Check with:
SELECT current_database();
Then check for the right table and schema name:
SELECT * FROM pg_tables
WHERE tablename ~* 'V5TableName'; -- ~* matches case-insensitive
The first riddle should be solved at this point.
Check your DB spelling and possible near-duplicates with:
SELECT datname FROM pg_database;
The call is without double-quotes (like you tried correctly), but requires correct capitalization:
SELECT pg_size_pretty(pg_database_size('MyDbName'));
Note the subtle difference (as documented in the manual):
pg_database_size() takes oid or name. So pass the case-sensitive database name without double-quotes.
pg_total_relation_size() takes regclass. So pass the case-sensitive relation name with double-quotes if you need to preserve capitalization.
pg_database_size() has to differ because there is no dedicated object identifier type for databases (no regdatabase).
The gist of it: avoid double-quoted identifiers in Postgres if at all possible. It makes your life easier.
Related
I've got a hashtags table in my mysql db, with a string(512) column called tag. I want to do a case sensitive search using Yii2's ActiveQuery, like this:
$expTags = ['one','two','three'];
Hashtag::find()->where(["IN","tag",$expTags])->select(["id"]);
In mysql, this usually means prefixing BINARY outside every value, or prefixing the column name. I tried both, I even tried "IN BINARY", nothing worked.
How to do this? I need case sensitive search, and I don't want to modify the table / column collation just to do this.
previous answer here got it pretty close:
$expTags = ['one','two','three'];
Hashtag::find()->where(["BINARY IN","tag",$expTags])->select(["id"]);
BINARY IN (used as operator) causes a syntax error (for mysql at least)
Hashtag::find()->where('BINARY tag in(:tag)', ['tag'=> $expTags])->select(["id"]);
and this hits the pdo problem of binding an array to a single param
this will work however:
Hashtag::find()->where(['BINARY(`tag`)' => $expTags])->select(["id"]);
you can try this:
$expTags = ['one','two','three'];
Hashtag::find()->where(["BINARY IN","tag",$expTags])->select(["id"]);
or
Hashtag::find()->where('BINARY tag in(:tag)', ['tag'=> $expTags])->select(["id"]);
I want to copy table from another db file but I fail and I can't get why. This is my code:
$db = new SQLite3($_SERVER['DOCUMENT_ROOT']."/db/098765.db");
$sql = "ATTACH DATABASE 'admin.db' AS admin ;
INSERT INTO 'table-1' SELECT * FROM 'admin.table-1';";
$db->query($sql);
I've read all the questions on this topic on this site, but no answer helped me.
Giving the full path to ATTACH DATABASE doesn't work. Creating table before inserting data also doesn't work.
The sqlite3 command line tool has a handy command called .dump that makes this task trivial:
sqlite3 admin.db '.dump "table-1"' | sqlite3 098765.db
This will create the table, all associated indexes and of course it will copy all the data.
Edit: For a more general solution, create a shell script (let's call it copy-table.sh) as follows:
#!/bin/bash
$src_db="$1"
$dst_db="$2"
$table="$3"
sqlite3 "$src_db" ".dump \"$table\"" | sqlite3 "$dst_db"
Then you can execute the script as follows
./copy-table.sh 'admin.db' '098765.db' 'table-1'
Obviously, you can execute the script anyway you want, e.g. from cron or from php.
Properly quote database object identifiers (table/column names etc) in your INSERT statement. Use use double quotes instead of single ones, which are for string literals. Better yet don't use dashes or other restricted characters in object names if possible (stick with alphanumerics and underscore).
Use exec() instead of query()
$dbPath = $_SERVER['DOCUMENT_ROOT'];
$adminDbPath = $dbPath; // Or something else
$db = new SQLite3("$dbPath/db/098765.db");
$db->exec("ATTACH DATABASE '$adminDbPath/admin.db' AS admin");
$db->exec('INSERT INTO "table-1" SELECT * FROM admin."table-1"');
^^^^ ^ ^ ^ ^
You can get exact copy of table by performing the following set of SQL statements:
(In context of connection to destination database)
attach '<source-db-full-name>' as sourceDb;
select sql from 'sqlite_master' where type = 'table' and name = '<name-of-table>';
// Execute result of previous statement.
// It will create empty table with
// schema identical to schema of source table
insert into '<name-of-table>' select * from sourceDb.[<name-of-table>];
detach sourceDb;
Using PHP 5.3.2 and Oracle 11G, I'm trying to pass an array from PHP into an oracle stored proc. Here is my PL/SQL:
create or replace type NUM_ARRAY as table of number;
create or replace package txa as
procedure upsert_txa_compliance_slct( v_compl_id_array in num_array);
end txa;
create or replace package body txa as
procedure upsert_txa_compliance_slct(v_compl_id_array in num_array)
is
begin
.
. -- sql code removed for brevity. package and body compile no errors
.
end upsert_txa_compliance_slct;
end;
The Query:
$sql = "begin txa.upsert_txa_compliance_slct(:my_array); end;";
And the PHP Code I've tried to bind the array and execute :
First:
<?
$this->conn = ociplogon($dbuser, $dbpass, $dbname);
$this->commit_mode = OCI_COMMIT_ON_SUCCESS;
$this->sth = #ociparse($this->conn, $sql);
oci_bind_array_by_name($this->sth,
':my_array',
$my_array,
count($my_array),
-1,
SQLT_CHR);
$r = #ociexecute($this->sth, $this->commit_mode);
?>
Which generates this error:
PLS-00306: wrong number or types of arguments in call to 'UPSERT_TXA_COMPLIANCE_SLCT'
I'm clearly passing 1 arg. So, what's wrong with/how do I fix the type issue?
Additionally I found this
http://www.oracle.com/technetwork/articles/seliverstov-multirows-098120.html
And tried it the old way using oci collection like so:
$collection = oci_new_collection($this->conn,"NUM_ARRAY");
After I changed my oracle type to this:
create or replace type NUM_ARRAY as varray(100) of number;
I got this error:
oci_new_collection(): ORA-22318: input type is not an array type
Any help would be MUCH appreciated.
EDIT 7:08PM ET Aug 14, 2014
I changed my php oci_bind function call to use SQLT_NUM as the type. This had no impact. Then I changed my package to include:
type num_array is table of number index by binary_integer;
( i also dropped the original num_array from my schema )
This change made it possible to pass my array to the stored proc, but then I can't use the array as a nested table like so:
delete
from my_table
where id not in (select column_value from table(v_compl_id_array));
I get this error when i try to compile the package body with that statement in it:
PL/SQL: ORA-22905: cannot access rows from a non-nested table item
And all the documentation tells me to return to the schema level type? But when I do I get that other error. I know I can find another way to do this using a loop over my pl/sql array, but I would really love to be able to use that schema level type.
The answer is this. You can't use a globally created or schema level type as a parameter to a stored procedure. PHP's oci_bind_array_by_name just doesn't seem to work with globally created types, but you need the globally created type to be able to use your array as a nested table in subselects. So.... here is how I got this to work. I'm MORE THAN HAPPY TO HEAR OTHER SOLUTIONS!! but for now, here's what I did.
-- globally create a type table of number
create or replace type num_array is table of number;
-- in my package i created an internal type table of number
type i_num_array is table of number index by binary_integer;
-- i then used i_num_array (internal type) as the type for my IN parameter to the procedure
upsert_TXA_compliance_slct( v_compl_id_array in i_num_array)
-- in my procedure i also created a variable that is the type of my globally created type
v_num_array num_array := num_array();
-- then i populated that variable in a loop inside my procedure with the values in my IN param
for i in 1 .. v_compl_id_array.count
loop
v_num_array.extend(1);
v_num_array(i) := v_compl_id_array(i);
end loop;
-- then i used v_num_array as my nested table so this now works:
delete from my_table where id in (select * from table(v_num_array));
Basically, I need to get some data out of a SQL Server 2005, using PHP.
Previously we used the mssql_* functions, however due to various server issues we are only now able to use odbc_* functions.
The table has various columns whose names have spaces in them, and before it is suggested.... no I cannot change them as this is a totally separate piece of software in another language and it would break it, I am just getting stats out of it.
Anywho, I had previously been accessing these columns by putting their names in square brackets, e.g. [column name] and it worked fine under the mssql_* functions, however when I do this:
$sql = "select top 1 [assessment name] as AssessmentName from bksb_Assessments";
$result = odbc_exec($db, $sql);
while($row = odbc_fetch_array($result))
{
var_dump($row);
}
It prints the results out as:
'assessment name' => string 'Mathematics E3 Diagnostic' (length=25)
So as you can see it is totally ignoring the alias I've given it and still calling it [assessment name].
But if I run the exact same thing in SQL Server Management Studio Express, it works fine and uses the alias.
I've tried various different combinations, such as quoting the alias, quoting the column, different brackets, etc... but no luck so far.
This isn't a huge issue, as I can change what my script uses to look for "assessment name" in the result array instead of the alias, but it's just a bit annoying that I couldn't work out why this was happening...
Cheers! :)
EDIT:
Actually i don't think the square brackets make a difference, just trying to alias any column isn't working with through php odbc, however I can still do something like CAST(whatever) AS 'alias' and that works fine... just not selecting a column as an alias...? :/
This is by no means a perfect solution, and I would love to learn the proper way to deal with this issue, but in the mean time, add +'' to each column, after the underlying column name, but before the AS alias and you should be able to circumvent this issue.
While attempting to troubleshoot this issue and determine why some of my team's stored procedures exhibited this behavior, I finally discovered why. What's strange is that we were only experiencing this issue with a few stored procedures, while most returned the the aliases as expected.
It appears that declaring at least one variable, whether or not it is being used, will prevent this particular bug from occurring. The variable can be of any type.
If you're just executing a SELECT query without using a stored procedure, use a DECLARE statement to define a variable before or after the statement:
// This works...
DECLARE #ignore TINYINT; SELECT EmployeeID AS employee_id FROM Employee;
// So does this...
SELECT EmployeeID AS employee_id FROM Employee; DECLARE #ignore TINYINT;
Now if you're running into this issue with your stored procedures, you can take the same approach above by defining a variable anywhere in the body.
One other thing I noticed is that if the stored procedure is defined with parameters, if your the parameter gets set or evaluated in something like an if statement, this bug will also not occur. For example,
// This works...
CREATE PROC get_employee(
#employee_id VARCHAR(16) = NULL
)
AS
IF (#employee_id IS NOT NULL)
BEGIN
SELECT FirstName AS first_name FROM Employee WHERE EmployeeID = #employee_id;
END
GO
Using SET:
// So does this...
CREATE PROC get_employee(
#employee_id VARCHAR(16) = NULL,
#ignore TINYINT
)
AS
SET #ignore = NULL;
SELECT FirstName AS first_name FROM Employee WHERE EmployeeID = #employee_id;
GO
I still don't quite understand the cause or nature of the bug; but these workarounds, similar to the type-casting hack above, appear to get around this annoying bug.
It's probably also worth mentioning that we didn't encounter this issue in Ubuntu 14.04 and PHP 5.4. As soon as we upgraded to Ubuntu 18.04 and PHP 7.2, that was when we began experiencing this issue. In both instances, we do have FreeTDS configured to use version 7.1, which is why we're baffled by this particular bug.
#dearsina's approach in fact seems to be one of the few ways to handle this bug.
However, this solution is not applicable to all datatypes. So for me, the only way to cover all needed columns was to CAST() the relevant column (where initially c.State would be of datatype bit):
SELECT
CAST(c.State AS nvarchar) AS 'customer_state'
FROM
customers AS c;
as else you might get an error message similar to
The data types bit and varchar are incompatible in the add operator.
Reference on CASTing large data sets: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/643b6eda-fa03-4ad3-85a1-051f02097c7f/how-much-do-cast-statements-affect-performance?forum=transactsql
Some further finding on this topic is a recently (November 2017) raised bug report at bugs.php.net claiming that the problem is related to FreeTDS: https://bugs.php.net/bug.php?id=75534.
This bug report contains an inofficial (and at least from my end untested) patch:
diff --git a/ext/odbc/php_odbc_includes.h b/ext/odbc/php_odbc_includes.h
index 93e2c96..8451bcd 100644
--- a/ext/odbc/php_odbc_includes.h
+++ b/ext/odbc/php_odbc_includes.h
## -292,18 +292,16 ## void odbc_sql_error(ODBC_SQL_ERROR_PARAMS);
#define PHP_ODBC_SQLCOLATTRIBUTE SQLColAttribute
#define PHP_ODBC_SQLALLOCSTMT(hdbc, phstmt) SQLAllocHandle(SQL_HANDLE_STMT, hdbc, phstmt)
-
-#define PHP_ODBC_SQL_DESC_NAME SQL_DESC_NAME
#else
#define IS_SQL_LONG(x) (x == SQL_LONGVARBINARY || x == SQL_LONGVARCHAR)
#define PHP_ODBC_SQLCOLATTRIBUTE SQLColAttributes
#define PHP_ODBC_SQLALLOCSTMT SQLAllocStmt
-
-#define PHP_ODBC_SQL_DESC_NAME SQL_COLUMN_NAME
#endif
#define IS_SQL_BINARY(x) (x == SQL_BINARY || x == SQL_VARBINARY || x == SQL_LONGVARBINARY)
+#define PHP_ODBC_SQL_DESC_NAME SQL_DESC_LABEL
+
PHP_ODBC_API ZEND_EXTERN_MODULE_GLOBALS(odbc)
#define ODBCG(v) ZEND_MODULE_GLOBALS_ACCESSOR(odbc, v)
Faced similar problem. The 4th parameter of odbc_connect did the trick in my case choosing cursor type SQL_CUR_USE_ODBC.
I'm trying to run the following PHP script to do a simple database query:
$db_host = "localhost";
$db_name = "showfinder";
$username = "user";
$password = "password";
$dbconn = pg_connect("host=$db_host dbname=$db_name user=$username password=$password")
or die('Could not connect: ' . pg_last_error());
$query = 'SELECT * FROM sf_bands LIMIT 10';
$result = pg_query($query) or die('Query failed: ' . pg_last_error());
This produces the following error:
Query failed: ERROR: relation "sf_bands" does not exist
In all the examples I can find where someone gets an error stating the relation does not exist, it's because they use uppercase letters in their table name. My table name does not have uppercase letters. Is there a way to query my table without including the database name, i.e. showfinder.sf_bands?
From what I've read, this error means that you're not referencing the table name correctly. One common reason is that the table is defined with a mixed-case spelling, and you're trying to query it with all lower-case.
In other words, the following fails:
CREATE TABLE "SF_Bands" ( ... );
SELECT * FROM sf_bands; -- ERROR!
Use double-quotes to delimit identifiers so you can use the specific mixed-case spelling as the table is defined.
SELECT * FROM "SF_Bands";
Re your comment, you can add a schema to the "search_path" so that when you reference a table name without qualifying its schema, the query will match that table name by checked each schema in order. Just like PATH in the shell or include_path in PHP, etc. You can check your current schema search path:
SHOW search_path
"$user",public
You can change your schema search path:
SET search_path TO showfinder,public;
See also http://www.postgresql.org/docs/8.3/static/ddl-schemas.html
I had problems with this and this is the story (sad but true) :
If your table name is all lower case like : accounts
you can use: select * from AcCounTs and it will work fine
If your table name is all lower case like : accounts
The following will fail:
select * from "AcCounTs"
If your table name is mixed case like : Accounts
The following will fail:
select * from accounts
If your table name is mixed case like : Accounts
The following will work OK:
select * from "Accounts"
I dont like remembering useless stuff like this but you have to ;)
Postgres process query different from other RDMS. Put schema name in double quote before your table name like this, "SCHEMA_NAME"."SF_Bands"
Put the dbname parameter in your connection string. It works for me while everything else failed.
Also when doing the select, specify the your_schema.your_table like this:
select * from my_schema.your_table
If a table name contains underscores or upper case, you need to surround it in double-quotes.
SELECT * from "Table_Name";
I had a similar problem on OSX but tried to play around with double and single quotes. For your case, you could try something like this
$query = 'SELECT * FROM "sf_bands"'; // NOTE: double quotes on "sf_Bands"
This is realy helpfull
SET search_path TO schema,public;
I digged this issues more, and found out about how to set this "search_path" by defoult for a new user in current database.
Open DataBase Properties then open Sheet "Variables"
and simply add this variable for your user with actual value.
So now your user will get this schema_name by defoult and you could use tableName without schemaName.
You must write schema name and table name in qutotation mark. As below:
select * from "schemaName"."tableName";
I had the same issue as above and I am using PostgreSQL 10.5.
I tried everything as above but nothing seems to be working.
Then I closed the pgadmin and opened a session for the PSQL terminal.
Logged into the PSQL and connected to the database and schema respectively :
\c <DATABASE_NAME>;
set search_path to <SCHEMA_NAME>;
Then, restarted the pgadmin console and then I was able to work without issue in the query-tool of the pagadmin.
For me the problem was, that I had used a query to that particular table while Django was initialized. Of course it will then throw an error, because those tables did not exist. In my case, it was a get_or_create method within a admin.py file, that was executed whenever the software ran any kind of operation (in this case the migration). Hope that helps someone.
In addition to Bill Karwin's answer =>
Yes, you should surround the table name with double quotes. However, be aware that most probably php will not allow you to just write simply:
$query = "SELECT * FROM "SF_Bands"";
Instead, you should use single quotes while surrounding the query as sav said.
$query = 'SELECT * FROM "SF_Bands"';
You have to add the schema first e.g.
SELECT * FROM place.user_place;
If you don't want to add that in all queries then try this:
SET search_path TO place;
Now it will works:
SELECT * FROM user_place;
Easiest workaround is Just change the table name and all column names to lowercase and your issue will be resolved.
For example:
Change Table_Name to table_name and
Change ColumnName to columnname
It might be silly for a few, but in my case - once I created the table I could able to query the table on the same session, but if I relogin with new session table does not exits.
Then I used commit just after creating the table and now I could able to find and query the table in the new session as well. Like this:
select * from my_schema.my_tbl;
Hope this would help a few.
Make sure that Table name doesn't contain any trailing whitespaces
Try this: SCHEMA_NAME.TABLE_NAME
I'd suggest checking if you run the migrations or if the table exists in the database.
I tried every good answer ( upvote > 10) but not works.
I met this problem in pgAdmin4.
so my solution is quite simple:
find the target table / scheme.
mouse right click, and click: query-tool
in this new query tool window, you can run your SQL without specifying set search_path to <SCHEMA_NAME>;
you can see the result: