How do you get the max_length for a mysql field - sql

MySQL is returning the current field value length in property max_length.
I there a way to get the correct values ?
ie Field part_code is a varchar(32) that returns 3 if it contains the value of "ABC" instead of the expected result of 32
EDIT
original mysql
//--------------------------------------------------------------------------
function build_fields(){
$idx = 0;
$num = #mysql_num_fields($this->qry);
while($idx < $num){
$field = mysql_fetch_field($this->qry, $idx);
$this->fields[$field->name] = $field;
$idx++;
}
} // function build_fields()
//--------------------------------------------------------------------------
new mysqli
//--------------------------------------------------------------------------
function build_fields(){
foreach(mysqli_fetch_fields($this->qry) as $name => $value){
$this->fields[$name] = (array) $value;
}
} // function build_fields()
//--------------------------------------------------------------------------
Used
DESCRIBE table_name
and parsed the varchar(32) and int(4,2)

SELECT CHARACTER_MAXIMUM_LENGTH,
COLUMN_TYPE
FROM `information_schema`.`COLUMNS`
WHERE TABLE_SCHEMA = 'MySchemaName'
AND TABLE_NAME = 'MyTableName'
AND COLUMN_NAME = 'MyColumnName'

In addition to Mark Baker's method , you can also get column information in several other ways:
SHOW COLUMNS FROM table_name where field='field_name';
// OR
DESCRIBE table_name field_name;
Then you need to parse 'Type' column (it's returned as varchar(32)) to get the max length.

Related

Can Laravel automatically switch between column = ? and column IS NULL depending on value?

When building a complex SQL query for Laravel, using ? as placeholders for parameters is great. However when the value is null, the SQL syntax needs to be changed from = ? to IS NULL. Plus, since the number of parameters is one less, I need to pass a different array.
To get it to work, I have written it like this, but there must be a better way:
if ($cohortId === null) {
// sql should be: column IS NULL
$sqlCohortString = "IS NULL";
$params = [
Carbon::today()->subDays(90),
// no cohort id here
];
} else {
// sql should be: column = ?
$sqlCohortString = "= ?";
$params = [
Carbon::today()->subDays(90),
$cohortId
];
}
$query = "SELECT items.`name`,
snapshots.`value`,
snapshots.`taken_at`,
FROM snapshots
INNER JOIN (
SELECT MAX(id) AS id, item_id
FROM snapshots
WHERE `taken_at` > ?
AND snapshots.`cohort_id` $sqlCohortString
GROUP BY item_id
) latest
ON latest.`id` = snapshots.`id`
INNER JOIN items
ON items.`id` = snapshots.`item_id`
ORDER by media_items.`slug` ASC
";
$chartData = DB::select($query, $params);
My question is: does Laravel have a way to detect null values and replace ? more intelligently?
PS: The SQL is for a chart, so I need the single highest snapshot value for each item.
You can use ->when to create a conditional where clause:
$data = DB::table('table')
->when($cohortId === null, function ($query) {
return $query->whereNull('cohort_id');
}, function ($query) use ($cohortId) {
// the "use" keyword provides access to "outer" variables
return $query->where('cohort_id', '=', $cohortId);
})
->where('taken_at', '>', $someDate)
->toSql();

Optional column update if provided value for column is not null

I have following table:
CREATE TABLE IF NOT EXISTS categories
(
id SERIAL PRIMARY KEY,
title CHARACTER VARYING(100) NOT NULL,
description CHARACTER VARYING(200) NULL,
category_type CHARACTER VARYING(100) NOT NULL
);
I am using pg-promise, and I want to provide optional update of columns:
categories.update = function (categoryTitle, toUpdateCategory) {
return this.db.oneOrNone(sql.update, [
categoryTitle,
toUpdateCategory.title, toUpdateCategory.category_type, toUpdateCategory.description,
])
}
categoryName - is required
toUpdateCategory.title - is required
toUpdateCategory.category_type - is optional (can be passed or undefined)
toUpdateCategory.description - is optional (can be passed or undefined)
I want to build UPDATE query for updating only provided columns:
UPDATE categories
SET title=$2,
// ... SET category_type=$3 if $3 is no NULL otherwise keep old category_type value
// ... SET description=$4 if $4 is no NULL otherwise keep old description value
WHERE title = $1
RETURNING *;
How can I achieve this optional column update in Postgres?
You could coalesce between the old and the new values:
UPDATE categories
SET title=$2,
category_type = COALESCE($3, category_type),
description = COALESCE($4, description) -- etc...
WHERE title = $1
The helpers syntax is best for any sort of dynamic logic with pg-promise:
/* logic for skipping columns: */
const skip = c => c.value === null || c.value === undefined;
/* reusable/static ColumnSet object: */
const cs = new pgp.helpers.ColumnSet(
[
'title',
{name: 'category_type', skip},
{name: 'description', skip}
],
{table: 'categories'});
categories.update = function(title, category) {
const condition = pgp.as.format(' WHERE title = $1', title);
const update = () => pgp.helpers.update(category, cs) + condition;
return this.db.none(update);
}
And if your optional column-properties do not even exist on the object when they are not specified, you can simplify the skip logic to just this (see Column logic):
const skip = c => !c.exists;
Used API: ColumnSet, helpers.update.
See also a very similar question: Skip update columns with pg-promise.

Laravel/SQL: where column Equals NOT and NULL

LARAVEL 5.4 (but probably it's a more general SQL question)
Hello! I have a table with a structure:
Suppose it's my model 'Table'.
I want a query which:
uses (receives) variables :
$id of array ['id', 'string', integer]
where string is '<' or '>'
$status_not_bad = bool;
(if true - include all rows where 'status' !== 'bad' AND 'status' IS NULL);
for example, we are given:
$id = [['id', '>', 0]];
$status_not_bad = true;
Table::thisquery() ... ->get();
"get rows where status is not bad and id > 0" returns rows 1 and 3.
but if we given:
$id = [['id', '<', 3]];
$status_not_bad = true;
Table::thisquery() ... ->get();
"get rows where status is not bad and id < 3" returns row 1
(it should be same query which return those results using those variables).
Probably you end with something like this:
if ($status_not_bad) {
$nStatus = 'bad';
} else {
$nStatus = 'good';
}
Table::thisquery()->where('status', '<>', $nStatus)
->whereNotNull('status')
->where($id[0], $id[1], $id[2])
->get();
But it would be a good idea to check $id keys first.
Since row id = 3 you need <= in your where statement to have that row included in the result set
$id = ['id', '<=', 3];
So, I this works:
$chain = Sample::when($status_not_bad, function($query){
return $query->where('status', '<>', 'bad')
->orwhereNull('status');
})
->where([$id])
->get();

How to return a JSON array from sql table with PhalconPHP

I have several tables that have JSON arrays stored within fields.
Using PHP PDO I am able to retrieve this data without issue using:
$query1 = $database->prepare("SELECT * FROM module_settings
WHERE project_token = ? AND module_id = ? ORDER BY id DESC LIMIT 1");
$query1->execute(array($page["project_token"], 2));
$idx = $query1->fetch(PDO::FETCH_ASSOC);
$idx["settings"] = json_decode($idx["settings"]);
This returns a string like:
{"mid":"","module_id":"1","force_reg_enable":"1","force_reg_page_delay":"2"}
Attempting to gather the same data via PhalconPHP
$result = Modulesettings::findFirst( array(
'conditions' => 'project_token = "' . $token . '"' ,
'columns' => 'settings'
) );
var_dump($result);
Provides a result of
object(Phalcon\Mvc\Model\Row)#61 (1) { ["settings"]=> string(167) "{"text":"<\/a>
<\/a>
","class":""}" }
What do I need to do different in Phalcon to return the string as it is stored in the table?
Thank you.
You have 2 approach
First :
Get the settings with this structure :
$settings = $result->settings;
var_dump($settings);
Second :
First get array from resultset, then using the array element :
$res = $result->toArray();
var_dump($res['settings']);
Try it.
You can decode json right in your Modulesettings model declaration:
// handling result
function afterFetch() {
$this->settings = json_decode($this->settings);
}
// saving. Can use beforeCreate+beforeSave+beforeUpdate
// or write a Json filter.
function beforeValidation() {
$this->settings = json_encode($this->settings);
}

Datatables server side processing and column alias

In Datatables using server side processing, is it possible to use column alias when specifying the columns?
At the moment this works fine with:
$aColumns = array( 'datetime','username', 'user_ip', 'company', 'action' );
but I would like to change the format of the date using date format in MySQL so, in effect, I want to use:
$aColumns = array( 'DATE_FORMAT(datetime, "%d/%m/%Y - %H:%i:%s") as newdate';'username'; 'user_ip';'company'; 'action' );
The problem is that the alias has a comma and the aColumns array is comma seperated so it breaks when later, for example, it comes to:
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
FROM $sTable
$sWhere
$sOrder
$sLimit
";
Is there a way I can use the alias rather than the original value? Even simply changing the select statement does not work as aColumns is used throughout the script hence it needs that value to be set correctly
Thanks
Yes. I actually just struggled with this issue myself. Because the JSON output is determined through counting the amount of columns in the array, and because of the imploding array, you have to add your column alias to $sQuery instead of the $aColumns array. So you'll actually have one less column in your $aColumns array than you'll need. For example, in mine, I needed an alias called total created from multiplying price and qty. So I put all my unaliased columns in the $aColumns array, like this:
$aColumns = array( 'purchaseID', 'dateOfOrder', 'productID', 'price', 'QTY');
But then, in the $sQuery string that concatenates all the things necessary to create the proper query string, I added my column alias between the implode and FROM. Don't forget to put a comma after the implode though, because it doesn't add it for you. The original $sQuery string looks like this:
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
FROM `$sTable`
$sWhere
$dateSql
$sOrder
$sLimit
";
But mine, with the column alias added, looks like this:
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
, `price` * `QTY` AS `total` FROM `$sTable`
$sWhere
$dateSql
$sOrder
$sLimit
";
Finally, the last thing you have to do is alter the actual JSON output to make sure your extra column is accounted for in the FOR loop at the end right before the json_encode, because it inserts items into the $row array, which is what becomes 'aaData' (the returned row data), based on how many columns you've specified in the $aColumns array, and because you left out any you've aliased, the count will be wrong, and you will get an error that looks something like 'requested unknown parameter from data source row'. The original FOR loop looks like this:
while ( $aRow = mysql_fetch_array( $rResult ) )
{
$row = array();
for ( $i=0 ; $i<count($aColumns) ; $i++ )
{
if ( $aColumns[$i] == "version" )
{
/* Special output formatting for 'version' column */
$row[] = ($aRow[ $aColumns[$i] ]=="0") ? '-' : $aRow[ $aColumns[$i] ];
}
else if ( $aColumns[$i] != ' ' )
{
/* General output */
$row[] = $aRow[ $aColumns[$i] ];
}
}
$output['aaData'][] = $row;
}
Like I said, this FOR loop works based off the COUNT of the $aColumns array, and since I've added an alias, it's going to cut my results short. It's not going to return the last element in the array containing the returned columns, so I'm going to alter the code to look like this:
for ( $i=0 ; $i<count($aColumns) + 1; $i++ )
{
if ($i < count($aColumns)){
if ( $aColumns[$i] == "version" )
{
/* Special output formatting for 'version' column */
$row[] = ($aRow[ $aColumns[$i] ]=="0") ? '-' : $aRow[ $aColumns[$i] ];
}
else if ( $aColumns[$i] != ' ' )
{
/* General output */
$row[] = $aRow[ $aColumns[$i] ];
}
}
else {
$row[] = $aRow['total'];
}
}
$output['aaData'][] = $row;
}
All I changed was the counter condition from $i<count($aColumns) to $i<count($aColumns) + 1, because my alias makes the column count one higher than what's in the array. And I've added a wrapping if-else that just says that if the counter, $i, is higher than the number of columns I've specified in the $aColumns array, then we've added all the columns in the array to the output data, so because I only added one extra alias column, then that means I can go ahead and just add that to the $row array, which contains all the output data from the returned rows.
You can actually add in as many aliased columns as you need, you just need to scale the code accordingly. Hope this helps!