Codeigniter:Using defined constants for table names in a join call - mysql

I have a defined constant for each of my database tables.
define('QTABLE','questions');
define('ATABLE','answers');
I would like to join these tables using a commonly referenced column "xid".
Here's how I'd do it if I referenced the actual name of the tables.
$this->db->from('questions');
$this->db->select('qcount,answers.xid,answers.aval');
$this->db->join('answers','questions.xid=answers.xid');
$gquery=$this->db->get();
But I do not want to reference the table names directly in the code in case we need to rename them later. How would I use the defined constants correctly to do this with Codeigniter's Active Records? I suspect it's all about escaping with the correct kind of single/double quotes.
I tried the following and it definitely does not work!
$this->db->from(Q-TABLE);
$this->db->select('qcount,ATABLE.xid,ATABLE.aval'); <----PROBLEM
$this->db->join(ATABLE,'QTABLE.xid=ATABLE.xid');<------PROBLEM
$gquery=$this->db->get();
Could you show me the way to the light?
mmiz

In your model
function __construct()
{
// Initialization of class
parent::__construct();
define('QTABLE','questions'); // define constant here in constructor
define('ATABLE','answers'); // define constant here in constructor
}
try query like this
$this->db->select('qcount,'.ATABLE.'.xid,'.ATABLE.'.aval');
$this->db->from(QTABLE);
$this->db->join(ATABLE,QTABLE.'.xid='.ATABLE.'.xid');
$query=$this->db->get();
echo $this->db->last_query(); exit;

Related

Automatically append database name to database table names

Is it possible to automatically append database name to a table name in laravel?
The issue is that I have to join data from multiple databases in single queries and sometime I am having to manually replace template names, which is a lot of hassle.
The only solution that I found is that I can append database name to the table name within a model, i.e.
class User extends Model
{
protected $table = 'database_name.table_name';
}
But with above we are losing support for table prefixes.
Example when database name is not applied:
$userQuery = User::where('id', 1)
->with('settings')
->select('some data');
DB::connection('x')
->table('table-on-different-connection')
->insertUsing(['some columns'], $userQuery);
$userQuery is on a different connection and database_name was not applied to the tables within that part of the query. Hence why insertUsing is trying to perform joins on connection x.
Laravel is not appending database name when generating SQL statements. To resolve that, you need to create your own MySQL wrapper and append the database name to the table name that way.
This is where the issue takes place:
vendor\laravel\framework\src\Illuminate\Database\Query\Grammar.php
public function wrapTable($table)
{
if (! $this->isExpression($table)) {
return $this->wrap($this->tablePrefix.$table, true);
}
return $this->getValue($table);
}
You need to override wrapTable method and append database name to the table that way.
i.e.
public function wrapTable($table)
{
$databaseName = $this->wrap('my_database'); // dynamically defined name here
if (! $this->isExpression($table)) {
$tableName = $this->wrap($this->tablePrefix.$table, true);
return "{$databaseName}.{$tableName}";
}
return $this->getValue("{$databaseName}.{$table}");
}
How you go about extending Grammar and override this method depends on your application and your needs. This can be done globally (i.e. via AppProvider) or for an individual query.

Laravel Schema Builder : Creating a binary(16) column

Using Laravel 5.5 and Mysql (10.1.19-MariaDB)
For a md5 hash I want a binary(16) column.
Let's call the colum url_hash
When using :
$table->binary('url_hash');
it will give me a BLOB column.
source : https://laravel.com/docs/5.5/migrations#creating-columns
I have seen all kind of hacks or plugins around the web for this , but what is the most simple one without any external plugins that could break on the next update?
Cheers
You can just set the character set to binary.
$table->char('url_hash', 16)->charset('binary');
This is actually shown as a real binary column type with a length of 16 in MySQL Workbench.
There shouldn't be any difference: https://stackoverflow.com/a/15335682/5412658
Extend the MySqlGrammar class, e.g. in app/MySqlGrammar.php:
namespace App;
use Illuminate\Support\Fluent;
class MySqlGrammar extends \Illuminate\Database\Schema\Grammars\MySqlGrammar {
protected function typeRealBinary(Fluent $column) {
return "binary({$column->length})";
}
}
Then use a macro to add your own column type:
DB::connection()->setSchemaGrammar(new \App\MySqlGrammar());
Blueprint::macro('realBinary', function($column, $length) {
return $this->addColumn('realBinary', $column, compact('length'));
});
Schema::create('table', function(Blueprint $table) {
$table->realBinary('url_hash', 16);
});
Laravel author recommends to do a DB:statement call and run the raw SQL.
If you are running migration, you could run this raw SQL after Schema::create:
DB::statement('ALTER TABLE table_name ADD url_hash binary(16) AFTER some_column');
Depends on use case, you could need to run this raw SQL to drop the column before dropping the table:
DB::statement('ALTER TABLE table_name DROP url_hash');

Get table checksum in Laravel 5.4

What do you use to get the checksum of a table in Laravel? Is there something already abstracted for this or you have to use raw commands?
You have to use raw commands, but it is pretty easy, just add this method to your model:
public static function checksum()
{
$tableName = with(new static)->getTable();
$query = sprintf('CHECKSUM TABLE %s', $tableName);
return \DB::select(\DB::raw($query))[0]->Checksum;
}
You can now call this method statically to get the checksum.

Best way to cache results of method with multiple parameters - Object as key in Dictionary?

At the beginning of a method I want to check if the method is called with these exact parameters before, and if so, return the result that was returned back then.
At first, with one parameter, I used a Dictionary, but now I need to check 3 parameters (a String, an Object and a boolean).
I tried making a custom Object like so:
var cacheKey:Object = { identifier:identifier, type:type, someBoolean:someBoolean };
//if key already exists, return it (not working)
if (resultCache[cacheKey]) return resultCache[cacheKey];
//else: create result ...
//and save it in the cache
resultCache[cacheKey] = result;
But this doesn't work, because the seccond time the function is called, the new cacheKey is not the same object as the first, even though it's properties are the same.
So my question is: is there a datatype that will check the properties of the object used as key for a matching key?
And what else is my best option? Create a cache for the keys as well? :/
Note there are two aspects to the technical solution: equality comparison and indexing.
The Cliff Notes version:
It's easy to do custom equality comparison
In order to perform indexing, you need to know more than whether one object is equal to another -- you need to know which is object is "bigger" than the other.
If all of your properties are primitives you should squash them into a single string and use an Object to keep track of them (NOT a Dictionary).
If you need to compare some of the individual properties for reference equality you're going to have a write a function to determine which set of properties is bigger than the other, and then make your own collection class that uses the output of the comparison function to implement its own a binary search tree based indexing.
If the number of unique sets of arguments is in the several hundreds or less AND you do need reference comparison for your Object argument, just use an Array and the some method to do a naive comparison to all cached keys. Only you know how expensive your actual method is, so it's up to you to decide what lookup cost (which depends on the number of unique arguments provided to the function) is acceptable.
Equality comparison
To address equality comparison it is easy enough to write some code to compare objects for the values of their properties, rather than for reference equality. The following function enforces strict set comparison, so that both objects must contain exactly the same properties (no additional properties on either object allowed) with the same values:
public static propsEqual(obj1:Object, obj2:Object):Boolean {
for(key1:* in obj1) {
if(obj2[key1] === undefined)
return false;
if(obj2[key1] != obj2[key1])
return false;
}
for(key2:* in obj2)
if(obj1[key2] === undefined)
return false;
return true;
}
You could speed it up by eliminating the second for loop with the tradeoff that {A:1, B:2} will be deemed equal to {A:1, B:2, C:'An extra property'}.
Indexing
The problem with this in your case is that you lose the indexing that a Dictionary provides for reference equality or that an Object provides for string keys. You would have to compare each new set of function arguments to the entire list of previously seen arguments, such as using Array.some. I use the field currentArgs and the method to avoid generating a new closure every time.
private var cachedArgs:Array = [];
private var currentArgs:Object;
function yourMethod(stringArg:String, objArg:Object, boolArg:Boolean):* {
currentArgs = { stringArg:stringArg, objArg:objArg, boolArg:boolArg };
var iveSeenThisBefore:Boolean = cachedArgs.some(compareToCurrent);
if(!iveSeenThisBefore)
cachedArgs.push(currentArgs);
}
function compareToCurrent(obj:Object):Boolean {
return someUtil.propsEqual(obj, currentArgs);
}
This means comparison will be O(n) time, where n is the ever increasing number of unique sets of function arguments.
If all the arguments to your function are primitive, see the very similar question In AS3, where do you draw the line between Dictionary and ArrayCollection?. The title doesn't sound very similar but the solution in the accepted answer (yes I wrote it) addresses the exact same techinical issue -- using multiple primitive values as a single compound key. The basic gist in your case would be:
private var cachedArgs:Object = {};
function yourMethod(stringArg:String, objArg:Object, boolArg:Boolean):* {
var argKey:String = stringArg + objArg.toString() + (boolArg ? 'T' : 'F');
if(cachedArgs[argKey] === undefined)
cachedArgs[argKey] = _yourMethod(stringArg, objArg, boolArg);
return cachedArgs[argKey];
}
private function _yourMethod(stringArg:String, objArg:Object, boolArg:Boolean):* {
// Do stuff
return something;
}
If you really need to determine which reference is "bigger" than another (as the Dictionary does internally) you're going to have to wade into some ugly stuff, since Adobe has not yet provided any API to retrieve the "value" / "address" of a reference. The best thing I've found so far is this interesting hack: How can I get an instance's "memory location" in ActionScript?. Without doing a bunch of performance tests I don't know if using this hack to compare references will kill the advantages gained by binary search tree indexnig. Naturally it would depend on the number of keys.

MATLAB: Is there a method to better organize functions for experiments?

I will run a set of experiments. The main method evaluated has the following signature:
[Model threshold] = detect(...
TrainNeg, TrainPos, nf, nT, factors, ...
removeEachStage, applyEstEachStage, removeFeatures);
where removeEachStage, applyEstEachStage, and removeFeatures are booleans. You can see that if I reverse the order of any of these boolean parameters I may get wrong results.
Is there a method in MATLAB that allows better organization in order to minimize this kind of error? Or is there any tool I can use to protect me against these errors?
Organization with a struct
You could input a struct that has these parameters as it's fields.
For example a structure with fields
setts.TrainNeg
.TrainPos
.nf
.nT
.factors
.removeEachStage
.applyEstEachStage
.removeFeatures
That way when you set the fields it is clear what the field is, unlike a function call where you have to remember the order of the parameters.
Then your function call becomes
[Model threshold] = detect(setts);
and your function definition would be something like
function [model, threshold] = detect(setts)
Then simply replace the occurrences of e.g. param with setts.param.
Mixed approach
You can also mix this approach with your current one if you prefer, e.g.
[Model threshold] = detect(in1, in2, setts);
if you wanted to still explicitly include in1 and in2, and bundle the rest into setts.
OOP approach
Another option is to turn detect into a class. The benefit to this is that a detect object would then have member variables with fixed names, as opposed to structs where if you make a typo when setting a field you just create a new field with the misspelled name.
For example
classdef detect()
properties
TrainNeg = [];
TrainPos = [];
nf = [];
nT = [];
factors = [];
removeEachStage = [];
applyEstEachStage = [];
removeFeatures =[];
end
methods
function run(self)
% Put the old detect code in here, use e.g. self.TrainNeg to access member variables (aka properties)
end
end