Postgresql SELECT without hardcoding item - sql

I have a simple PostgreSql query that looks like:
$params = array();
if ($audienceId === x) {
// all teachers
$pullRecipients = $db -> prepare(
"SELECT email FROM app.employees WHERE emp_cat_id = 1 AND active is true");
}
$pullRecipients -> execute($params);
I'm running the queries based on a drop down select, so that if for example the user selects TEACHERS, the above query is run. How can I select for instance the emp_cat_id or even the category name TEACHERS without hard coding them in the query?

change statement to something like
SELECT email
FROM app.employees
WHERE emp_cat_id = ? AND active IS true
and make sure your $params is equal to something like array($POST["drop-down_value])
and if you want to allow text value - use join, something like:
SELECT email
FROM app.employees
WHERE emp_cat_id = (SELECT id FROM emp_cat WHERE name = ?)
AND active IS true

Related

Conditional Doobie query with Option field

I have following
case class Request(name:Option[String], age: Option[Int], address: Option[List[String]])
And I want to construct a query like this the conditions should apply if and only if the field is defined:
val req = Request(Some("abc"), Some(27), Some(List["add1", "add2"])
select name, age, email from user where name = "abc" AND age = 27 AND address in("add1", "add2");
I went through doobies documentation and found about fragments which allow me to do the following.
val baseSql: Fragment = sql"select name, age, email from user";
val nameFilter: Option[Fragment] = name.map(x => fr" name = $x")
val ageFilter: Option[Fragment] = age.map(x => fr" age = $x")
val addressFilter: Option[Fragment] = address.map(x => fr " address IN ( " ++ x.map(y => fr "$y").intercalate(fr",") ++ fr" )"
val q = baseSql ++ whereAndOpt(nameFilter, ageFilter, addressFilter)
from my understanding the query should look like this if all the fields are defined:
select name, age, email from user where name = "abc" AND age = 27 AND address in("add1","add2");
but the query looks like this:
select name, age, email from user where name = ? AND age = ? AND address in(?);
What is wrong here I am not able to find that.
Thanks in advance !!!!
Everything is fine.
Doobie prevents SQL injections by SQL functionality where you use ? in your query (parametrized query), and then pass the values that database should put into the consecutive ? arguments.
Think like this: if someone posted name = "''; DROP table users; SELECT 1". Then you'd end up with
select name, age, email from user where name = ''; DROP table users; SELECT 1
which could be a problem.
Since the database is inserting arguments for you, it can do it after the parsing of a raw text, when such injection is impossible. This functionality is used not only by Doobie but by virtually every modern library or framework that let you talk to database at level higher than plain driver.
So what you see is a parametrized query in the way that database will see it, you just don't see the parameters that will be passed to it.

PostgreSQL stored function with multiple queries

I'm working on a PostgreSQL function, but having a real struggle with it. It's not my main area so that's probably why, but I wanted to see if this is doable.
I'm trying to create a function to generate records based on year.
In php I'd do something along the lines of:
function recordsByYear($year=''){
$years = array();
if(empty($year)){
$sql = "SELECT year FROM myTable GROUP BY year ORDER BY year;";
$res = $conn->query($sql);
if($res !== false){
$data = $res->fetchAll(PDO::FETCH_COLUMN);
foreach($data as $oneYear){
$years[] = $oneYear;
}
}
}
else{
$years[] = $year;
}
foreach($years as $thisYear){
//do some queries based on $thisYear
}
}
But I'd like to create a function inside of PostgreSQL, and struggling because I'm not familiar enough with how it all works. I'd like to return a table. I can do some basic stuff, but haven't been able to get something like this working where I have one query then loop through those results running an additional query for each year, then combine the results of that second query and spit out the results as a table.
Is hard to guess without more information but you probably need a JOIN
SELECT *
FROM (
SELECT DISTINCT year
FROM myTable
) y
JOIN ( SELECT year, ... <some query>
....
) t
ON y.year = t.year
PostgreSQL function:
CREATE FUNCTION record_years() RETURNS SETOF int AS $$
SELECT DISTINCT year FROM myTable ORDER BY 1
$$ LANGUAGE SQL;
Your PHP code:
$sql = "SELECT record_years()";
or
$sql = "SELECT year FROM record_years() AS year";
or alternatively all values in a single row, as a JSON array:
$sql = "SELECT array_to_json(ARRAY(SELECT record_years())) AS arr";
$res = $conn->query($sql);
if($res !== false){
$row = $res->fetch();
$years[] = json_decode($row['arr']);
}

How to escape parameter in like sql query using active record?

Have query with parentesis:
SELECT *
FROM users
WHERE company_id = 1 AND (
name LIKE "%smith%" OR
last_name LIKE "%smith%"
)
But in codeigniter have:
$query_members = $this->db
->select('users.*')
->from('users')
->like(array('users.names' => $search))
->or_like(array('users.last_name' => $search))
->where(array('users.company_id' => 1));
This generate:
SELECT *
FROM users
WHERE
name LIKE '%smith%' OR
last_name LIKE '%smith%' AND
company_id = 1;
And does not works, i need ((a or b) and c), not (a or b and c). I found solution here: Codeigniter parentheses in dynamic Active Record query but the variable is escaped with full quotes, i need escape with "%" pre and pos value. I have this:
$search_escaped = $this->db->escape($search);
$query_members = $this->db
->select('users.*')
->from('users')
->where('(users.names LIKE "%'.$search_escaped.'%" OR users.last_name LIKE "%'.$search_escaped.'%")')
->where(array('members.company_id' => (int)$company_id));
But the query add bad quotes:
SELECT `users`.*
FROM `users`
WHERE (users.names LIKE "%'smith'%" OR users.last_name LIKE "%'smith'%")
AND `members`.`company_id` = 2
The "%'smith'%" is bad quoted. How I can solve this by using active record of codeigniter 3.0.0?

PDO Grab data where name = name

so I've been trying to grab data from a name, like this
So my table look like this:
Table = database then ID, ip, name.
So when a name is entered I want to check if there is an IP attached to it in my database if there is then print all ip's else don't do anything..
This is very easy you didn't show what you tried.
A simple select would do it:
$stmt = $pdo->prepare('SELECT ip FROM `databases` WHERE name = :name');
$stmt->execute(array('name'=>$name));
$row = $stmt->fetch(FETCH_ASSOC);
then compare in PHP:
if($row['ip'] == $_SERVER['REMOTE_ADDR']){
//IP attached to it in my database
}

SELECT MAX query returns only 1 variable + codeigniter

I use codeigniter and have an issue about SELECT MAX ... I couldnot find any solution at google search...
it looks like it returns only id :/ it's giving error for other columns of table :/
Appreciate helps, thanks!
Model:
function get_default()
{
$this->db->select_max('id');
$query = $this->db->getwhere('gallery', array('cat' => "1"));
if($query->num_rows() > 0) {
return $query->row_array(); //return the row as an associative array
}
}
Controller:
$default_img = $this->blabla_model->get_default();
$data['default_id'] = $default_img['id']; // it returns this
$data['default_name'] = $default_img['gname']; // it gives error for gname although it is at table
To achieve your goal, your desire SQL can look something like:
SELECT *
FROM gallery
WHERE cat = '1'
ORDER BY id
LIMIT 1
And to utilise CodeIgniter database class:
$this->db->select('*');
$this->db->where('cat', '1');
$this->db->order_by('id', 'DESC');
$this->db->limit(1);
$query = $this->db->get('gallery');
That is correct: select_max returns only the value, and no other column. From the specs:
$this->db->select_max('age');
$query = $this->db->get('members');
// Produces: SELECT MAX(age) as age FROM members
You may want to read the value first, and run another query.
For an id, you can also use $id = $this->db->insert_id();
See also: http://www.hostfree.com/user_guide/database/active_record.html#select
CodeIgniter will select * if nothing else is selected. By setting select_max() you are populating the select property and therefore saying you ONLY want that value.
To solve this, just combine select_max() and select():
$this->db->select('somefield, another_field');
$this->db->select_max('age');
or even:
$this->db->select('sometable.*', FALSE);
$this->db->select_max('age');
Should do the trick.
It should be noted that you may of course also utilize your own "custom" sql statements in CodeIgniter, you're not limited to the active record sql functions you've outlined thus far. Another active record function that CodeIgniter provides is $this->db->query(); Which allows you to submit your own SQL queries (including variables) like so:
function foo_bar()
{
$cat = 1;
$limit = 1;
$sql = "
SELECT *
FROM gallery
WHERE cat = $cat
ORDER BY id
LIMIT $limit
";
$data['query'] = $this->db->query($sql);
return $data['query'];
}
Recently I have been utilizing this quite a bit as I've been doing some queries that are difficult (if not annoying or impossible) to pull off with CI's explicit active record functions.
I realize you may know this already, just thought it would help to include for posterity.
2 helpful links are:
http://codeigniter.com/user_guide/database/results.html
http://codeigniter.com/user_guide/database/examples.html