How to iterate Oracle Query Cursor field in PHP? - oracle11g

I hope you can help me, I need to get the data of an SQL query in Oracle 11g, which one of its fields is cursor type, this is the query:
SELECT m.nombre, m.icono, (CURSOR(SELECT p.nombre nombre_permiso, p.url
FROM permiso p
WHERE p.fk_menu = m.pk_menu
AND p.estado = 'A'
ORDER BY p.orden)) permisos FROM menu m WHERE m.estado = 'A' ORDER BY orden;
When I execute it with PHP, the field namepermiso appears as a ResourceId type, but it should give me the fields it contains, I suppose that is the type of field, the PHP code I use is the following:
$sql = "DECLARE
my_cursor SYS_REFCURSOR;
BEGIN
OPEN my_cursor FOR SELECT m.nombre, m.icono, (CURSOR(SELECT p.nombre nombre_permiso, p.url
FROM permiso p
WHERE p.fk_menu = m.pk_menu
AND p.estado = 'A'
ORDER BY p.orden)) permisos
FROM menu m
WHERE m.estado = 'A'
ORDER BY orden;
:cursor := my_cursor;
END; ";
$conn = $this->db->conn_id;
$curs = oci_new_cursor($conn);
$stid = oci_parse($conn, $sql);
oci_bind_by_name($stid, ":cursor", $curs, -1, OCI_B_CURSOR);
oci_execute($stid);
oci_execute($curs);
while (($row = oci_fetch_array($curs, OCI_ASSOC + OCI_RETURN_NULLS)) != false)
{
var_dump($row);
}
oci_free_statement($stid);
oci_free_statement($curs);
The var_dump show this:
array(3) { ["NOMBRE"]=> string(16) "Parametrización" ["ICONO"]=> string(11) "fa fa-gears" ["PERMISOS"]=> resource(46) of type (oci8 statement) } array(3) { ["NOMBRE"]=> string(24) "Gestión de información" ["ICONO"]=> string(10) "fa-sitemap" ["PERMISOS"]=> resource(47) of type (oci8 statement) }
thank you very much!

Related

Add record to database if not already there

I want to add a value to my table if it is not already there. I cant use UNIQUE as there will be multiple lines with the same value. I've tried below but $result returns bool(true). How can I do that?
$ishashinDB = $db->prepare('SELECT COUNT(*) FROM mytable WHERE hash = :hash;');
$ishashinDB->bindValue(':hash', $Ihash);
$result = $ishashinDB->execute();
var_dump($result);
if ($result == 0) {
$addhash = $db -> prepare("INSERT INTO mytable (hash) VALUES (:hash)");
$addhash -> bindParam(':hash', $Ihash, PDO::PARAM_STR);
$addhash -> execute();
}
Use this below execute:
$result = $ishashinDB->setFetchMode(PDO::FETCH_ASSOC);

Get Avg value in Doctrine / symfony

i try to get AVG value in doctrine, in my Repositoru i do this:
public function getFotoSpecifica($idFoto) {
$q = $this->createQueryBuilder('f');
$q->leftJoin("f.foto_votata", 'v');
$q->where('f.id =:idFoto');
$q->andWhere('(f.foto_privata IS NULL OR f.foto_privata != 1)');
$q->andWhere('(f.foto_eliminata IS NULL OR f.foto_eliminata != 1)');
$q->expr()->avg('v.punteggio', true);
$q->setParameter('idFoto', $idFoto);
$dql = $q->getQuery();
$results = $dql->getArrayResult();
return $results;
}
but i don't find any value avg, i see all my object...i try to use createQuery in my controller but i have many errors like: Error: Invalid PathExpression. Must be a StateFieldPathExpression. ( this is a foreign key)
mySql query is:
SELECT profilo_id, proprietario_id, round(AVG( punteggio ),2) as avg_rate, SUM(punteggio) as score, foto_id, count(*) as numero_votanti
FROM prof_voto_foto
WHERE foto_id = ?
Assuming the variable name for the foreign key is named $foto and the entity is ProfVotoFoto
In your controller you can do something like this.
$em = $this->getDoctrine()->getManager();
$q=$em->createQuery("
SELECT profilo_id, proprietario_id, round(AVG( punteggio ),2) as avg_rate,
SUM(punteggio) as score, foto_id, count(*) as numero_votanti
FROM YourBundleName:ProfVotoFoto f
WHERE f.foto = :idFoto
")
->setPArameter('idFoto',$idFoto);
$averageResult = $q->getSingleResult();
You are forget to add a select statement to query. Also possible requires to add group by.
->addSelect('AVG(v.punteggio) as punteggio_avg')

SQL stored procedure sent data for "IN" condition

I have a stored procedure and it has where condition using 'IN' key word. So I want to send more than one value to stored procedure .
This is my stored procedure:
ALTER PROCEDURE [dbo].[xxx]
#COM_KEY varchar(max) = NULL
AS
BEGIN
SELECT
UserName, UserId
FROM
company
WHERE
(COM_KEY IN (#COM_KEY))
END
So I pass the value in here
string companyID = "";
for (int i = 0; i < lbCompanies.Items.Count; i++)
{
if (i == 0)
{
companyID += Convert.ToInt32(lbCompanies.Items[i].Value);
}
else
{
companyID += "," + Convert.ToInt32(lbCompanies.Items[i].Value);
}
}
DataSet ApproveList = DataRepository.TUsersProvider.xxx(companyID);
but there is an error
Conversion failed when converting the varchar value '3087,4058' to data type int
How can I solve it?
You cannot pass a comma-delimited string into #COM_KEY. You should pass an array.
One way to accomplish this task would be using Table-Valued Parameters.
Have a look at this article, under Solution #3: TSQL: Passing array/list/set to stored procedure (MS SQL Server).
In essence, you treat your series of ints as a table you apply JOIN upon, and not query it via WHERE ... IN () phrase.
You can create a UserDefinedFunction which parses the string and puts each integer extracted into a table to solve this issue
CREATE Function fnSplitter (#IDs Varchar(100) )
Returns #Tbl_IDs Table (ID Int) As
Begin
-- Append comma
Set #IDs = #IDs + ','
-- Indexes to keep the position of searching
Declare #Pos1 Int
Declare #pos2 Int
-- Start from first character
Set #Pos1=1
Set #Pos2=1
While #Pos1<Len(#IDs)
Begin
Set #Pos1 = CharIndex(',',#IDs,#Pos1)
Insert #Tbl_IDs Select Cast(Substring(#IDs,#Pos2,#Pos1-#Pos2) As Int)
-- Go to next non comma character
Set #Pos2=#Pos1+1
-- Search from the next charcater
Set #Pos1 = #Pos1+1
End
Return
End
Now alter your stored procedure like this
ALTER PROCEDURE [dbo].[xxx]
#COM_KEY varchar(max) = NULL
AS
BEGIN
SELECT UserName, UserId
From company
WHERE COM_KEY IN (Select ID From dbo.fnSplitter(#COM_KEY))
END
Check this link for detailed Implemetation
The most trivial solution to your problem is to vale SQL string(for dynamic Query) and then execute the statement
ALTER PROCEDURE [dbo].[xxx]
#COM_KEY varchar(max) = NULL
AS
BEGIN
DECLARE #SQL nvarchar(MAX)
SET #SQL=N' SELECT
UserName, UserId
FROM
company
WHERE
(COM_KEY IN ('+#COM_KEY+'))'
EXCE #SQL
END
Solution mentioned by #ssilas777 is the sophisticated version for the same.
Also note that using IN is not always advisable. I have run into
query time out errors
when IN has lot of IDs
Change your code from:
if (i == 0)
{
companyID += Convert.ToInt32(lbCompanies.Items[i].Value);
}
else
{
companyID += "," + Convert.ToInt32(lbCompanies.Items[i].Value);
}
to:
if (i == 0)
{
companyID +="'" + Convert.ToInt32(lbCompanies.Items[i].Value) + "'";
}
else
{
companyID += ",'" + Convert.ToInt32(lbCompanies.Items[i].Value) + "'";
}

SQL use comma-separated values with IN clause

I am developing an ASP.NET application and passing a string value like "1,2,3,4" into a procedure to select those values which are IN (1,2,3,4) but its saying "Conversion failed when converting the varchar value '1,2,3,4' to data type int."
Here is the aspx code:
private void fillRoles()
{
/*Read in User Profile Data from database */
Database db = DatabaseFactory.CreateDatabase();
DbCommand cmd = db.GetStoredProcCommand("sp_getUserRoles");
db.AddInParameter(cmd, "#pGroupIDs", System.Data.DbType.String);
db.SetParameterValue(cmd, "#pGroupIDs", "1,2,3,4");
IDataReader reader = db.ExecuteReader(cmd);
DropDownListRole.DataTextField = "Group";
DropDownListRole.DataValueField = "ID";
while (reader.Read())
{
DropDownListRole.Items.Add((new ListItem(reader[1].ToString(), reader[0].ToString())));
}
reader.Close();
}
Here is my procedure:
CREATE Procedure [dbo].[sp_getUserRoles](#pGroupIDs varchar(50))
AS BEGIN
SELECT * FROM CheckList_Groups Where id in (#pGroupIDs)
END
Here is a workaround I found to do what you are trying to achieve
CREATE Procedure [dbo].[sp_getUserRoles](
#pGroupIDs varchar(50)
)
As
BEGIN
SELECT * FROM CheckList_Groups Where (',' + #pGroupIDs +',' LIKE '%,' + CONVERT(VARCHAR, id) + ',%')
End
This gets your comma delimited list and compares it to the id's(which are represented like so ',1,', ',2,' etc) in the table using LIKE
If you dont want to use dynamic sql, the best way ive found is to create a function which turns a delimited string into a table, something like this works for an Integer list:
CREATE FUNCTION [dbo].[StringToIntList]
(#str VARCHAR (MAX), #delimeter CHAR (1))
RETURNS
#result TABLE (
[ID] INT NULL)
AS
BEGIN
DECLARE #x XML
SET #x = '<t>' + REPLACE(#str, #delimeter, '</t><t>') + '</t>'
INSERT INTO #result
SELECT DISTINCT x.i.value('.', 'int') AS token
FROM #x.nodes('//t') x(i)
ORDER BY 1
RETURN
END
Then use that in your sp:
CREATE Procedure [dbo].[sp_getUserRoles](
#pGroupIDs varchar(50)
)
As
BEGIN
SELECT * FROM CheckList_Groups Where id in (
SELECT ID FROM dbo.StringToIntList(#pGroupIds,',')
)
End
Sure it can't do that,
The generated query would be sth like this
SELECT * FROM CheckList_Groups Where id in ('1,2,3,4')
and sure it can't be executed.
you can build the query in your stored procedure then execute it with exec
'SELECT * FROM CheckList_Groups Where id in (' + #pGroupIDs + ')'
or
SELECT * FROM CheckList_Groups Where charindex(','+id+',' , #pGroupIDs)>0
but you first must add the ',' to start and end of your parameter in your c# code
It is not possible to put those values (the comma separated string) in a parameter-value.
What you'll have to do, is to create the SQL Statement in your stored procedure dynamically, by string concatenation. You'll have to execute it with the sp_executesql stored procedure then.
CREATE PROCEDURE [dbo].[getUserRoles]( #groupIds NVARCHAR(50) )
AS BEGIN
DECLARE #statement NVARCHAR(255)
SELECT #statement = N'SELECT * FROM CheckList_Groups Where id in ( ' + #pGroupIDs + N')'
execute sp_executesql #statement
END
Also, not that I named the SP getUserRoles instead of sp_getUserRoles.
The reason is very simple: when you execute a stored procedure whose name starts with sp_, then SQL Server will first query the master database to find that stored procedure, which causes a performance hit offcourse.
The way you are trying to do this is slightly wrong. You will need to use EXECUTE in order to achieve this.
CREATE PROCEDURE [dbo].[sp_getUserRoles](#pGroupIDs nvarchar(50))
As
BEGIN
EXECUTE (N'SELECT * FROM CheckList_Groups Where id in (' + #pGroupIDs + ')';
END
DECLARE #TagId NVARCHAR(100) = '43,81'
SELECT * FROM TABLE WHERE TagId IN (SELECT TRIM(VALUE) FROM STRING_SPLIT( #TagId , ',' ) )
USE STRING_SPLIT FUNCTION FOR THIS
You need to use SP_executesql to achieve this functionllity
CREATE Procedure [dbo].[sp_getUserRoles](
#pGroupIDs varchar(50)
)
As
BEGIN
EXECUTE sp_executesql
N'SELECT * FROM CheckList_Groups Where id in (#pGroupIDs)',
N'#level varchar(50)',
#level = #pGroupIDs;
End
The IN clause can't take a bound parameter like that. What it's being given when the query is actually created is SELECT * FROM CheckList_Groups Where id in ('1,2,3,4'). Essentially the IN clause is being passed a single string.
First create function -
Just run this code
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[CSVToTable] (#InStr VARCHAR(MAX))
RETURNS #TempTab TABLE
(id int not null)
AS
BEGIN
;-- Ensure input ends with comma
SET #InStr = REPLACE(#InStr + ',', ',,', ',')
DECLARE #SP INT
DECLARE #VALUE VARCHAR(1000)
WHILE PATINDEX('%,%', #INSTR ) <> 0
BEGIN
SELECT #SP = PATINDEX('%,%',#INSTR)
SELECT #VALUE = LEFT(#INSTR , #SP - 1)
SELECT #INSTR = STUFF(#INSTR, 1, #SP, '')
INSERT INTO #TempTab(id) VALUES (#VALUE)
END
RETURN
END
GO
Then -
Use function in bracket with select statment -
DECLARE #LIST VARCHAR(200)
SET #LIST = '1,3'
SELECT Id, Descr FROM CSVDemo WHERE Id IN (SELECT * FROM dbo.CSVToTable(#LIST))

how to drop all indexes of a sqlite table

I have a simple question: How to drop all indexes of a sqlite table?
I have multiple indexes created with random name.
Regards,
Pentium10
To get all index names in a database
SELECT name FROM sqlite_master WHERE type == 'index'
For a specific table:
SELECT name FROM sqlite_master WHERE type == 'index' AND tbl_name == 'table Name'
Then in your language, iterate thought the results and drop them
FOR x IN RESULTSET
SQL = "DROP INDEX " & X
I'm not aware that you can drop ALL indexes in one command - IMO you have to drop each by name. See also: http://www.sqlite.org/lang_dropindex.html Also, check this out for additional info: Drop all tables command
#!/bin/bash
DB=your_sqlite.db
TABLE="some_table"
INDEXES="$(echo "SELECT name FROM sqlite_master WHERE type == 'index' AND tbl_name = '$TABLE;" | sqlite3 $DB)"
for i in $INDEXES; do
echo "DROP INDEX '$i';" | sqlite3 $DB
done
Make sure no other process accesses the database, while you call this script, or if thats not possible add
PRAGMA busy_timeout=20000;
in each echo that you send to the database
Here is how to do it in Android (with the help of Robert's answer and this SQLite page:
/*
* Drop all indexes.
*/
try {
Cursor cursor = db.rawQuery("SELECT name FROM sqlite_master WHERE type == 'index'", null);
int numIndexes = (cursor == null) ? 0 : cursor.getCount();
Log.d(LOG_TAG, "Num indexes to drop: " + numIndexes);
if (numIndexes > 0) {
String[] indexNames = new String[numIndexes];
int i = 0;
while (cursor.moveToNext()) {
indexNames[i++] = cursor.getString(cursor.getColumnIndexOrThrow("name"));
}
for (i = 0; i < indexNames.length; i++) {
Log.d(LOG_TAG, "Dropping index: " + indexNames[i] + "...");
db.execSQL("DROP INDEX " + indexNames[i]);
Log.e(LOG_TAG, "...index dropped!");
}
}
}
catch(Exception e) {
Log.e(LOG_TAG, "Error dropping index", e);
}

Resources