psql insert into if else - sql

I want to make it so that when creating a user, the first user receives $ 1000 on the wallet, and the rest - $ 10 (user_id - pk)
I made this request
INSERT INTO users (user_id, login, balance, encrypted_password)
select 1, 'login',
case
when user_id = 1 then (login = 'login', balance= 1000, encrypted_password = 'password')
else (login = 'login', balance = 10, encrypted_password = 'password')
end as user_id
RETURNING user_id
but when I make this request, I get the error:
ERROR: ERROR: column "user_id" does not exist
LINE 4: when #user_id == 0 then (login = 'login', balance= '...
^
HINT: There is a "user_id" column in the "users" table, but it cannot be referenced from this part of the query.
SQL state: 42703
character: 103

Related

Laravel whereHas in many to many column id ambigious

There are my 3 tables:
- conversations:
- id
- name
- users:
- id
- name
- conversation_user:
- id
- conversation_id
- user_id
Model conversation:
public function members() {
return $this->belongsToMany(User::class, 'conversation_user');
}
Model user:
public function conversations() {
return $this->hasMany(Conversation::class, 'conversation_user');
}
I want to retrieve if 2 users has already a conversation set.
My request
Conversation::withCount('members')->having('members_count', '==', 2)
->whereHas('members', function($query) use($user){
$query->where('id', $user);
})->whereHas('members', function($query) use($auth){
$query->where('id', $auth->id);
})->first();
1 conversation has at least 2 members, so it can have more; but here in my functionality I have input that search for users, and on click a user, I want to retrieve if the user logged in and the user selected has already a conversation.
But with my query I get this error:
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous (SQL: select conversations., (select count() from users inner join conversation_user on users.id = conversation_user.user_id where conversations.id = conversation_user.conversation_id) as members_count from conversations where exists (select * from users inner join conversation_user on users.id = conversation_user.user_id where conversations.id = conversation_user.conversation_id and id = 2) and exists (select * from users inner join conversation_user on users.id = conversation_user.user_id where conversations.id = conversation_user.conversation_id and id = 1) having members_count = == limit 1)
you have to set the table names to avoid ambiguity:
Conversation::withCount('members')->having('members_count', '==', 2)
->whereHas('members', function($query) use($user){
$query->where('users.id', $user);
})->whereHas('members', function($query) use($auth){
$query->where('users.id', $auth->id);
})->first();

How to insert a username if it doesn't already exist with a postgresql POOL query

I am making a game and I recently added a server database score saver but I can't figure out how to insert a username only if it doesn't already exist here is the following query:
const addUser = (req, res) => {
const {username, score} = req.body;
pool.query(
'INSERT INTO userlist (username, score) VALUES ($1, $2)',
[username, score],
(err) => {
if(err){
throw err;
}
res.status(201).json({status: "success", message: "User added."});
},
);
}
I am guessing I'll have to change the query
also here is my SQL code for creating the table:
CREATE TABLE userlist(
ID SERIAL PRIMARY KEY,
username VARCHAR(255),
score VARCHAR(255)
);
The best way to handle this is to let the database validate the uniqueness of the username:
alter table userlist add constraint unq_userlist_usename unique(username);
Now if you attempt to insert a single row, then it will return an error if the row already exists.
If you don't want an error you can use an on conflict clause. However, in this case, an exception seems useful to notify the user that username already exists.
use an if statement to identify if the username exist and then update it
if (Users::where('name', $request->user_name)->exists()) {
return response()->json(['record exist']);
} else {
$save = new Users;
$save->name = $request->user_name;
$save->save();
return response()->json(['User saved successfully.']);
}

Why this PDO parametrized query behave "strangely"?

Here i have edited my original question.
I have alswo answered it, in my next message.
I'm trying to get results from MySQL with parametrized php PDO query, but thing behaves strangley. I dont know if it is a bug, or I am doing something wrong or not seeing something obvious.
Lets suppose there are these two tables in database
CREATE TABLE `users` (
`user_id` int(11) NOT NULL PRIMARY KEY
)
CREATE TABLE `users_contacts` (
`contact_id` int(11) NOT NULL PRIMARY KEY ,
`user_id` int(11) DEFAULT NULL,
`type` varchar(45) DEFAULT NULL,
`value` varchar(255) DEFAULT NULL
)
Fill them with minimal data :
INSERT INTO `users` (`user_id`) VALUES (125);
INSERT INTO `users_contacts` (`contact_id`, `user_id`, `type`, `value`)
VALUES(11432, 125, 'email', 'losleyTyped#offten.stinks'),
(11433, 125, 'phone', '1234567'),
(564, 125, 'unit', '910');
And then you try to fetch data like this
$db_name = "";
$db_user = "";
$db_pass = "";
$db_pdo = new pdo("mysql:host=localhost;dbname=$db_name","$db_user","$db_pass");
$user = 125;
$user_unit_btm = 900;
$user_unit_top = $user_unit_btm + 100;
$upload_user = $db_pdo -> prepare("SELECT K.value AS unit
FROM users AS O,
users_contacts AS K
WHERE O.user_id = :user_id AND
K.user_id = O.user_id AND
K.type = 'unit' AND
K.value >= :unit_btm AND
K.value < :unit_top
");
$upload_user -> execute( [":user_id" => $user,
":unit_btm" => $user_unit_btm,
":unit_top" => $user_unit_top
]
);
$upload_user = $upload_user -> fetch(PDO::FETCH_ASSOC);
var_dump($upload_user);
var_dump will return false, but there is no error(err is 0000)
I have reduced the problem, and find that only one parameter ":organization" is problematic and cause for bizare behevior.
But if you replace " K.value < :unit_top "
with variable $user_unit_top
" K.value < $user_unit_top "
Then, query returns result!
Same thing if i replace " K.value < :unit_top " with literal 1000,
" K.value < 100"
Then query returns result!
Why is this happening?
As mentioned in my comment to your answer.
The PHP documentation on PDOStatement::execute states.
An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as PDO::PARAM_STR.
Source: https://www.php.net/manual/en/pdostatement.execute.php
Additionally PDOStatement::fetch() returns false when there are no more results or upon failure.
The return value of this function on success depends on the fetch type. In all cases, FALSE is returned on failure.
Example https://3v4l.org/NVECJ
$pdo = new \PDO('sqlite::memory:', null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
$pdo->query('CREATE TABLE foo(id INTEGER)');
$stmt = $pdo->prepare('SELECT * FROM foo');
$stmt->execute();
var_dump($stmt->fetch());
//bool(false)
If you need to explicitly define a data type, other than PDO::PARAM_STR for the parameter being sent to MySQL, you would use PDOStatement::bindParam or PDOStatement::bindValue
Example:
$upload_user = $db_pdo->prepare('SELECT
K.value AS unit
FROM users AS O,
users_contacts AS K
WHERE O.user_id = :user_id
AND K.user_id = O.user_id
AND K.type = \'unit\'
AND K.value >= :unit_btm
AND K.value < :unit_top');
$upload_user->bindValue(':user_id', $user, PDO::PARAM_INT);
$upload_user->bindValue(':unit_btm', $user_unit_btm, PDO::PARAM_INT);
$upload_user->bindValue(':unit_top', $user_unit_top, PDO::PARAM_INT);
$upload_user->execute();
An alternative would be to force data type casting on the parameter in the query.
$upload_user = $db_pdo->prepare('SELECT
K.value AS unit
FROM users AS O,
users_contacts AS K
WHERE O.user_id = :user_id
AND K.user_id = O.user_id
AND K.type = \'unit\'
AND K.value >= (:unit_btm - 0)
AND K.value < (:unit_top - 0)'); //CAST(:unit_top AS SIGNED)
$upload_user->execute([
':user_id' => $user,
':unit_btm' => $user_unit_btm,
':unit_top' => $user_unit_top
]);
Another contributing factor to your issue, is that MySQL will perform an automatic conversion to the column's data type for the comparison. Where other RDMBS, like PostgreSQL and SQLite3 do not perform the same conversions.
When an operator is used with operands of different types, type
conversion occurs to make the operands compatible. Some conversions
occur implicitly. For example, MySQL automatically converts strings to
numbers as necessary, and vice versa.
Source: https://dev.mysql.com/doc/refman/5.7/en/type-conversion.html
Since your initial column data type was VARCHAR, this resulted in the following from your testing.DB Fiddle
Initial query as PDOStatement::execute([1000]).
SELECT IF('910' > '1000', 'fail', 'pass') AS if_str_to_str;
| if_str_to_str |
| ------------- |
| fail |
Manually supplying integer to the Query
SELECT IF('910' > 1000, 'fail', 'pass') AS if_str_to_int;
| if_str_to_int |
| ------------- |
| pass |
After changing the database column data type and using PDOStatement::execute([1000])
SELECT IF(910 > '1000', 'fail', 'pass') AS if_int_to_str;
| if_int_to_str |
| ------------- |
| pass |
Using PDOStatement::bindValue(':param', '1000', PDO::PARAM_INT) or ('1000' - 0)
SELECT IF('910' > CAST('1000' AS SIGNED), 'fail', 'pass') AS if_str_to_typecast_int;
| if_str_to_typecast_int |
| ---------------------- |
| pass |
Here is an answer if somebody else find him self with similar problem
Why is this happening?
I think it is because Php or MySQL automatic type recognition/casting
Take a look of the table users_contacts the column named 'value' is of type VARCHAR (because the table is something like EAV data model).
In prepared query from my question on this line
K.value < :unit_top
PHP/MySQL is supposing that parameter :unit_top is the same datatype as K.value column (VARCHAR) so it compares-collation them like strings ???, and the string "910" is later then "1000".
If you replace parameter ":unit_top" with variable $user_unit_top
K.value < $user_unit_top
or a literal
K.value < 1000
Then Php is doing numeric comparison, and "1000" is bigger then "910"
*If you change table users_contacts column named 'value' from VARCHAR to INT then the
K.value < :unit_top
comparison will be numeric
I think this is very inconsistent behavior, because if you do the following
$a = "1000";
$b = " 910";
var_dump($a < $b);
PHP will do automatic type casting and then numeric commparison, ...
Am I wrong ?

Incorrect usage of UPDATE and ORDER BY In Laravel eloquent

Iam trying to update 'sortOrder' column based on a given list of ids.
For example, if the given IDs are:
$orderList = ['id' =>'1','id' =>'5','id' =>'3']
ID of '1' => 'sortOrder column' = 1
ID of '5' => 'sortOrder column' = 2
ID of '3' => 'sortOrder column' = 3
Query statement:
$ids_array = array_pluck($orderList, 'id');
$ids_string = implode(',', $ids_array);
DB::statement(DB::raw('set #rownum=0'));
$result = DB::table('requirements')
->join('sections', 'sections.id', '=', 'requirements.section_id')
->whereIn('id', $ids_array)
->orderByRaw("FIELD(requirements.id, {$ids_string})")
->update([
'requirements.sortOrder' => DB::raw('#rownum := #rownum + 1'),
]);
But when I try to update using this query, I am getting an error:
SQLSTATE[HY000]: General error: 1221 Incorrect usage of UPDATE and ORDER BY

How to join two table id and validate a particular field?

Sorry for the fuorviant title but I'll trying to explain what I'm try to do. So, I've two table ea_users and ea_user_settings.
ea_users - STRUCTURE
id | data|
5 | 0
ea_user_settings - STRUCTURE
|id | username|
5 Sandokan
Now what I'm trying to do is validate if certain username already exists in the system. The table ea_users contain the id, that rapresents the id of a single user, and the data field (0 user not removed, also 1 user deleted).
In the ea_user_settings table I've all settings of my users. Now a possible idea for check if a certain username already exist is this:
public function validate_username($username, $user_id)
{
$num_rows = $this->db->get_where('ea_user_settings',
array('username' => $username, 'id_users <> ' => $user_id))->num_rows();
return ($num_rows > 0) ? FALSE : TRUE;
}
This function have two parameters: username and user_id, the username that's going to be inserted and the user_id (if this is valorized means that I'm actually stay update the user so I don't need to check on it row if the username already exists).
Actually all working good but I want to check if the username exists for only the user with the data equal to 0, if the data is 1 the username is available 'cause it's deleted. I don't know if the situation is more clear. How I can achieve that in a single query?
You can try something like this
public function validate_username($username, $user_id)
{
$num_rows =
$this->db->select('*')
->from('ea_user_settings')
->join('ea_users', 'ea_user_settings.id_users = ea_users.id', 'left')
->where(array('ea_user_settings.username' => $username, 'ea_user_settings.id_users <> ' => $user_id, 'ea_users.data' => 1))
->get();
return ($num_rows->num_rows() > 0) ? 'We have this username and it was deleted!' : 'This username was not deleted';
}