We have a PHP project using Codeigniter framework(v3). The project is using MySQL database hosted on AWS RDS instance.
We are planning to migrate the database to Postgres. The problem is quotes. The existing project is using single quotes outside the query string.
For eg.,
$query = $this->db->select('o.*,concat("O",o.id) as id, c.name as customer,w.name as warehouse,a.name as account,a.type as channel,
IFNULL(oi.qty,0) as qty, IFNULL(oi.picked_qty,0) as picked_qty, IFNULL(oi.boxes,0) as boxes,IFNULL(oi.packed_qty,0) as packed_qty,
IFNULL(oi.shipped_qty,0) as shipped_qty', FALSE)
->join('customers c', 'c.id=o.customer_id')
->join('warehouses w', 'w.id=o.warehouse_id')
->join('accounts a', 'a.id=o.account_id')
->join('(select order_id, sum(qty) as qty, sum(boxes) as boxes,sum(picked_qty) as picked_qty, sum(packed_qty) as packed_qty,
sum(shipped_qty) as shipped_qty, group_concat(IFNULL(order_items.sku,"null") separator "|") as skus,
group_concat(order_items.in_stock separator "|") as in_stock, group_concat(distinct(order_items.upc) separator "|") as upcs,
group_concat(distinct(order_items.ean) separator "|") as eans , group_concat(brand_name) brands, group_concat(product_category) categories
from order_items left join upc on order_items.sku = upc.sku group by order_items.order_id) oi', 'oi.order_id=o.id', 'left')
->from('orders o');
The working Postgres version is:
$query = $this->db->select("o.*,concat('O',o.id) as id, c.name as customer,w.name as warehouse,a.name as account,a.type as channel,
coalesce(oi.qty,0) as qty, coalesce(oi.picked_qty,0) as picked_qty, coalesce(oi.boxes,0) as boxes,coalesce(oi.packed_qty,0) as packed_qty,
coalesce(oi.shipped_qty,0) as shipped_qty", FALSE)
->join("customers c", "c.id=o.customer_id")
->join("warehouses w", "w.id=o.warehouse_id")
->join("accounts a", "a.id=o.account_id")
->join("(select order_id, sum(qty) as qty, sum(boxes) as boxes,sum(picked_qty) as picked_qty, sum(packed_qty) as packed_qty,
sum(shipped_qty) as shipped_qty, string_agg(coalesce(order_items.sku,'null'), '|') as skus,
string_agg(order_items.in_stock, '|') as in_stock, string_agg(distinct(order_items.upc), '|') as upcs,
string_agg(distinct order_items.ean, '|') as eans , string_agg(brand_name, '') brands, string_agg(product_category, '') categories
from order_items left join upc on order_items.sku = upc.sku group by order_items.order_id) oi", 'oi.order_id=o.id', 'left')
->from("orders o");
Notice the difference in single and double quotes in the above queries. Codeigniter expects query string inside double quotes when working with Postgres, we can not wrap a query using single quotes and use double quotes inside it,for eg concat('O',o.id) is correct while concat("O",o.id) is not correct using Codeigniter active record
We have hundreds of these queries in the project using several Codeigniter's active record functions like this->db->query, this->db->select, and it's a nightmare converting them all manually, I tried writing a script for it but its not much useful either because of php variables embedded inside queries like '.$cond.'
Is there something that can help to migrate all these queries quickly?
Note - We are using 'postgre' databse driver in database.php file for migrating to Postgres
Related
I am creating a website that will show specific records to some folks in the company here. I am using PHP, HTML and MYSLQ to create it.
This is the basic layout I am trying to present:
It is an html website, and each row has collapsible rows on 2 levels:
Reference Number > Entries > Invoices
So in this logic, a Reference Number can have one or multiple Entries and an Entry can have one or multiple Invoices.
The html table is a no brainer, the problem is to feed the data into the website.
How I made it work...
Using PHP I created a procedure that first queries the database for the References, then I do a while loop to go through the References and then using the reference number I query the Entries and do a while loop to go through them and use the Entry Number to query for the Invoices.
Now, I am an amateur coder, but I do know that putting the query inside a while loop is extremely bad practice. So I am struggling to making this work properly.
Furthermore, I want this to work by using stored procedures so that all the querying happens on mysql server, rather than on the client side.
Here are the queries:
Query 1 (Main level):
SELECT
oc.sNumCajaTrailer AS Caja,
oc.dFechaCruce AS FechaSalida,
t.sNombre AS Transportista,
tfc.sCveTrafico AS Reference <--- This is the key for the next query
FROM cb_detalle_orden_carga doc
JOIN cb_orden_carga oc ON doc.iConsecutivoOrdenCarga = oc.iConsecutivo
JOIN cu_transfer t ON oc.sCveTransfer = t.sCveTransfer
JOIN cb_trafico tfc ON doc.sCveTrafico = tfc.sCveTrafico
JOIN cu_cliente cte ON tfc.sCveCliente = cte.sCveCliente
WHERE
(oc.dFechaCruce IS NULL OR oc.dFechaCruce IN (fechaSalida))
AND tfc.sCveCliente = 'CLT_6840' AND (doc.sCveTrafico LIKE '%N16%' OR doc.sCveTrafico LIKE '%N17%')
GROUP BY doc.sCveTrafico
Query 2 (FirstSubLevel)
SELECT b.sCveEntradaBodega AS Entry, <----- This is the key for next query
cp.sNombreProveedor AS NombreProveedor,
b.dFechaIngreso AS FechaIngreso,
b.iCantidadBultos AS Bultos,
cb.sDescripcion AS TipoBultos
FROM cb_bulto b
JOIN cb_entrada_bodega eb ON b.sCveEntradaBodega = eb.sCveEntradaBodega
JOIN cu_cliente_proveedor cp ON eb.sCveProveedor = cp.sCveProveedor
AND cp.sCveCliente = eb.sCveCliente
JOIN cb_detalle_orden_carga doc ON b.iConsecutivo = doc.iConsecutivoBulto
JOIN cb_orden_carga oc ON doc.iConsecutivoOrdenCarga = oc.iConsecutivo
JOIN ct_bulto cb ON b.sCveBulto = cb.sCveBulto
WHERE b.sCveTrafico = Reference
Query 3 (Second and last sublevel)
SELECT
f.sNumero AS numFactura,
eb.sNumTalon AS numGuia,
pf.sCveClienteProveedorProducto AS numParte,
pf.iCantidadProducto AS cantidadProducto,
f.sNumeroPedido AS numOrden,
b.iCantidadBultos AS cantidadBultos,
tb.sDescripcion AS tipoBultos
FROM
cb_bulto b
JOIN cb_relacion_remesa_banco_facturas rbf ON b.iConsecutivo = rbf.iConsecutivoBulto
JOIN cb_factura f ON rbf.iFolio = f.iFolio
JOIN cb_entrada_bodega eb ON b.sCveEntradaBodega = eb.sCveEntradaBodega
JOIN cb_producto_factura pf ON f.iFolio = pf.iFolio
JOIN ct_bulto tb ON b.sCveBulto = tb.sCveBulto
WHERE
b.sCveEntradaBodega = Entry
Any ideas????!!!!
I am trying to insert some information to a new table in my database. For this I query information from two tables and a xref table, then I try to do the insert as I usually do. This is not working.
Here is the code,
$query = "select listaA.product_s_desc, category_name, listaA.product_desc, listaA.product_sku
from listaA, jos_vm_category, jos_vm_product_category_xref
where listaA.product_id = jos_vm_product_category_xref.product_id
and jos_vm_category.category_id = jos_vm_product_category_xref.category_id limit 10";
$result = mysql_query($query);
$row = mysql_fetch_array($result) or die;
do{
$imagen = 'http://accesoriosazteca.mx/imagesite/'.$row['listaA.product_sku'].".png";
mysql_query("insert into lista_importat (id, activo, sku, nombre, categoria, descripcion_corta, descripcion_larga, pedidos, mostrar_precio, imagen)
values ('$row['listaA.product_id']', '1', '$row['listaA.product_sku']', '$row['listaA.product_s_desc']', '', '$row['listaA.product_s_desc']', '$row['listaA.product_desc']', '0', '0', '$imagen')");
}while($row = mysql_fetch_array($result));
With the code above I get a blank screen, and nothing is inserted into the new table. Any ideas?
If the query starting...
select listaA.product_s_desc, ...
returns a resultset, the first column in the resultset will have a column name of product_s_desc, not listaA.product_s_desc.
(Running the query in the mysql command line client will demonstrate this behavior.)
To reference to the value of that column in $row:
$row['product_s_desc']
Note that the query does not return a column with a name of listaA.product_id.
A few notes, beyond answering the question you asked:
For the benefit of readers, I recommend you ditch the old school comma syntax for the join operation and use the JOIN keyword in it's place, and relocate the join predicates from the WHERE clause to an ON clause. I also recommend the use of short table aliases, and also qualifying ALL column references. For example:
SELECT a.product_s_desc
, c.category_name
, a.product_desc
, a.product_sku
FROM listaA a
JOIN jos_vm_product_category_xref r
ON r.product_id = a.product_id
JOIN jos_vm_category c
ON c.category_id = r.category_id
ORDER BY 1
LIMIT 10
sql="INSERT INTO maticna
(formCompany,formPlace,formDate,formPerson,formCollect
,formOffer,formDescribe,formBarkod,formSubject,formWorking
,formStatus,formRevision)
SELECT
company.formCompany, company.formPlace
, $formDate AS formDate
, $formPerson AS formPerson
, $formCollect AS formCollect
, $formOffer AS formOffer
, $formDescribe AS formDescribe
, $formBarkod AS formBarkod
, inv.formSubject, work.rnNo
, $formStatus AS formStatus
, $formRevision AS formRevision)"
."FROM company, inv, work
WHERE inv.formBarkod='$formBarkod'";
Something doesn't work with this code? Could anyone help with this code or some better method?
$formDate = mysql_real_escape_string($formdate);
$formPerson = mysql_real_escape_string($formPerson);
....
//For each and every $var you inject in the SQL statement.
$sql="INSERT INTO maticna
(formCompany,formPlace,formDate,formPerson,formCollect
,formOffer,formDescribe,formBarkod,formSubject,formWorking
,formStatus,formRevision)
SELECT
c.formCompany, c.formPlace
, '$formDate' AS formDate
, '$formPerson' AS formPerson
, '$formCollect' AS formCollect
, '$formOffer' AS formOffer
, '$formDescribe' AS formDescribe
, '$formBarkod' AS formBarkod
, i.formSubject, w.rnNo
, '$formStatus' AS formStatus
, '$formRevision' AS formRevision
FROM company c
INNER JOIN work w ON (w.id = i.work_id)
INNER JOIN inv i ON (i.company_id = c.id)
WHERE i.formBarkod= '$formBarkod' ";
Mistakes you make
1. Don't use implicit join syntax, it leads to cross joins; always use explicit join syntax instead.
2. You did not have any join criteria.
3. All $vars need to be escaped always.
4. All $vars, be they numbers or not need to be quoted in the SQL-statement.
5. Minor syntax error in the insert statement.
Shouldn't you insert VALUES before the select?
INSERT INTO maticna (...) VALUES (SELECT ...)
I have two primary MySQL tables (profiles and contacts) with many supplementary tables (prefixed by prm_). They are accessed and manipulated via PHP.
In this instance I am querying the profiles table where I will retrieve an Owner ID and a Breeder ID. This will then be referenced against the contacts table where the information on the Owners and Breeders is kept.
I received great help here on another question regarding joins and aliases, where I was also furnished with the following query. Unfortunately, I am having huge difficulty in actually echoing out the results. Every single site that deals with Self Joins and Aliases provide lovely examples of the queries - but then skip to "and this Outputs etc etc etc". How does it output????
SELECT *
FROM (
SELECT *
FROM profiles
INNER JOIN prm_breedgender
ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN contacts ownerContact
ON profiles.ProfileOwnerID = ownerContact.ContactID
LEFT JOIN prm_breedcolour
ON profiles.ProfileAdultColourID = prm_breedcolour.BreedColourID
LEFT JOIN prm_breedcolourmodifier
ON profiles.ProfileColourModifierID = prm_breedcolourmodifier.BreedColourModifierID
) ilv LEFT JOIN contacts breederContact
ON ilv.ProfileBreederID = breederContact.ContactID
WHERE ProfileName != 'Unknown'
ORDER BY ilv.ProfileGenderID, ilv.ProfileName ASC $limit
Coupled with this is the following PHP:
$owner = ($row['ownerContact.ContactFirstName'] . ' ' . $row['ownerContact.ContactLastName']);
$breeder = ($row['breederContact.ContactFirstName'] . ' ' . $row['breederContact.ContactLastName']);
All details EXCEPT the contacts (gender, colour, etc.) return fine. The $owner and $breeder variables are empty.
Any help in settling this for me would be massively appreciated.
EDIT: My final WORKING query:
SELECT ProfileOwnerID, ProfileBreederID,
ProfileGenderID, ProfileAdultColourID, ProfileColourModifierID, ProfileYearOfBirth,
ProfileYearOfDeath, ProfileLocalRegNumber, ProfileName,
owner.ContactFirstName AS owner_fname, owner.ContactLastName AS owner_lname,
breeder.ContactFirstName AS breeder_fname, breeder.ContactLastName AS breeder_lname,
BreedGender, BreedColour, BreedColourModifier
FROM profiles
LEFT JOIN contacts AS owner
ON ProfileOwnerID = owner.ContactID
LEFT JOIN contacts AS breeder
ON ProfileBreederID = breeder.ContactID
LEFT JOIN prm_breedgender
ON ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN prm_breedcolour
ON ProfileAdultColourID = prm_breedcolour.BreedColourID
LEFT JOIN prm_breedcolourmodifier
ON ProfileColourModifierID = prm_breedcolourmodifier.BreedColourModifierID
WHERE ProfileName != 'Unknown'
ORDER BY ProfileGenderID, ProfileName ASC $limit
Which I could then output by:
$owner = ($row['owner_lname'] . ' - ' . $row['owner_fname']);
Many Thanks to All!
I guess you're using the mysql_fetch_array or the mysql_fetch_assoc-functions to get the array from the result-set?
In this case, you can't use
$row['ownerContact.ContactFirstName']
as the PHP-Docs read:
If two or more columns of the result have the same field names, the
last column will take precedence. To access the other column(s) of the
same name, you must use the numeric index of the column or make an
alias for the column. For aliased columns, you cannot access the
contents with the original column name.
So, you can either use an AS in your SQL-query to set other names for the doubled rows or use the numbered indexes to access them.
This could then look like this:
Using AS in your Query
In your standard SQL-query, the columns in the result-set are named like the columns which their values come from. Sometimes, this can be a problem due to a naming-conflict. Using the AS-command in your query, you can rename a column in the result-set:
SELECT something AS "something_else"
FROM your_table
This will rename the something-column to something_else (you can leave the ""-quotes out, but I think it makes it more readable).
Using the column-indexes for the array
The other way to go is using the column-index instead of their names. Look at this query:
SELECT first_name, last_name
FROM some_table
The result-set will contain two columns, 0 ==> first_name and 1 ==> last_name. You can use this numbers to access the column in your result-set:
$row[0] // would be the "first_name"-column
$row[1] // would be the "last_name"-column
To be able to use the column-index, you'll need to use mysql_fetch_row or the mysql_fetch_assoc-function, which offers an associative array, a numeric array, or both ("both" is standard).
you need to replace the * with the data you need , and the similar ones you have to make aliases too :
ownerContact.ContactFirstName as owner_ContactFirstName
and
breederContact.ContactFirstName as breeder_ContactFirstName .
like this :
select ownerContact.ContactFirstName as owner_ContactFirstName , breederContact.ContactFirstName as breeder_ContactFirstName from profiles join ownerContact ... etc
in this way you will write :
$owner = ($row['owner_ContactFirstName'] . ' ' . $row['owner_ContactLastName']);
$breeder = ($row['breeder_ContactFirstName'] . ' ' . $row['breeder_ContactLastName']);
You cannot specify table alias when you access row using php. Accessing it by $row['ContactFirstName'] would work if you didn't have 2 fields with the same name. In this case whatever ContactFirstName appears second overwrites the first.
Change your query to use fields aliases, so you can do $owner = $row['Owner_ContactFirstName'].
Another option I'm not 100% sure is to access field by index, not by name(e.g. $owner=$row[11]). Even if it works I don't recommend to do so, you will have a lot of troubles if change your query a bit.
On outer select You have only two tables:
(inner select) as ilv
contacts as breederContact
there is no ownerContact at all
I'm getting a product listing. Each product may have 1 or more image, I only want to return the first image.
$this->db->select('p.product_id, p.product_name i.img_name, i.img_ext');
$this->db->join('products_images i', 'i.product_id = p.product_id', 'left');
$query = $this->db->get('products p');
Is there anyway to limit the db->join to 1 record using the CI active record class?
Add $this->db->limit(1); before calling $this->db->get('products p');. See the docs at ellislab.com: search the page for limit.
EDIT: I misread the fact that you were trying to apply the LIMIT to the internal JOIN statement.
No. Since you can not do a LIMIT on an internal JOIN statement in regular SQL you can not do it with Code Igniter's ActiveRecord class.
You can achieve what you want using $this->db->group_by with a left join:
$this->db->select('products.id, products.product_name, products_images.img_name, products_images.img_ext');
$this->db->from('products');
$this->db->join('products_images', 'products_images.product_id = products.id', 'left');
$this->db->group_by('products.id');
$query = $this->db->get();
This should give you results by products.id (without repetition of products), with the first matching record from products_images joined to each result row. If there's no matching row from the joined table (i.e. if an image is missing) you'll get null values for the products_images fields but will still see a result from the products table.
To expand on #Femi's answer:
There's no good way to limit the JOIN, and, in fact, you don't really want to. Assuming both products_image.product_id and products.id have indexes (and they absolutely should if you're going to join against them repeatedly) when the database engine does a join, it uses the indexes to determine what rows it needs to fetch. Then the engine uses the results to determine where on the disk to find the records it needs. If you
You should be able to see the difference by running these SQL statements:
EXPLAIN
SELECT p.product_id, p.product_name, i.img_name, i.img_ext
FROM products p
LEFT JOIN products_images i
ON i.product_id = p.product_id
as opposed to:
EXPLAIN
SELECT p.product_id, p.product_name, i.img_name, i.img_ext
FROM (SELECT product_id, product_name FROM products) p
LEFT JOIN (SELECT img_name, img_ext FROM products_images) i
ON i.product_id = p.product_id
The first query should have an index, the second one will not. There should be a performance difference if there's a significant number of rows the the DB.
Had this issue too the way I solved it was iterating over the results and removing the current object if the product_id had existed in a previous one. Create a array, push the product_id's to it while checking if they are repeats.
$product_array = array();
$i = 0;
foreach($result as $r){
if(in_array($r->product_id,$product_array)){
unset($result[$i]);
}else{
array_push($product_array,$r->product_id);
}
$i++;
}
$result = array_values($result); //re-index result array
Now $result is what we want