We have a simple MySql table which stores settings for our app. We normally use our code to just select all the data and do the following:-
Override values based on a given Environment. This works fine, as the code would take care of replacing values based on env and create an object with correct values, but now thinking of just pushing the job to the MySql db.
Table
| SettingName | SettingValue | Environment |
| ------------|----------------|-------------|
| ApiUrl | api1.xxx.com | Dev |
| ApiUrl | api2.xxx.com | Test |
| ApiUrl | api3.xxx.com | Live |
| SomeSetting | 0 | Test |
| SomeSetting | 1 | Live |
In some cases we may have Settings for each Enviroment in others we have just 2.
There will always be at least 2 Test/Live.
I would like to achieve the following:
Given 2 Environments like Dev as the current and Test as the fallback I want a table that will give me Dev setting if it exists or fallback to Test if it does not.
I have tried the following:-
SET #defaultEnv = 'Test'; //Fallback if settings don't exist for #env
SET #env = 'Live';
SELECT s.SettingName,IFNULL(filter.SettingValue,s.SettingValue) as SettingValue
FROM Settings AS s
LEFT JOIN (SELECT * FROM Settings WHERE Environment=#env) AS filter ON filter.SettingName = s.SettingName
WHERE s.Environment = #defaultEnv;
This does not seem to bring in correct values as required based on the correct Environment.
Do I need a CASE statement or any other way?
Related
Possibly a duplicate been searching for the specific answer i need but couldnt find it. I have two simple tables
Source :
| Id | companyName | adress |
|----|-------------|---------|
| 1 | aquatics | street1 |
| 2 | rivers | street2 |
target :
| Id | nameCompany | companyAdress |
|----|-------------|----------------|
| 1 | aquatics | street1 |
| 2 | rivers | |
I simplified the matter, I have two sets of data the source table is extern data en i as a dev want to update my table with the extern data.
So we see that in the source everything is filled in.
I miss some info. In this case i miss the adress.
How can i run a query that checks: your row is incomplete. Lemme update this target row with the source data.
Only problem is. Extern data uses a different name voor the same columns as i have.
Been a couple of days with mysql. So pls try to explain noob friendly tried some thing but i couldnt figure it out
Below query updates companyAdress on target table if adress column on Source table is not equal to companyAdress on target table.
If you only need to update the empty values for target.companyAdress you should change the condition where s.adress <> t.companyAdress to where t.companyAdress =''
update target t
inner join `Source` s
on t.nameCompany=s.companyName
set t.companyAdress=s.adress
where s.adress <> t.companyAdress ;
Demo: https://www.db-fiddle.com/f/pB6b5xrgPKCivFWcpQHsyE/0
I'm building a sql statement like the one below in a rails app :-
bank_ids = params[:bank_ids] # comes from end user or simply, is a user input.
sql_string = "SELECT * FROM users WHERE bank_id IN (#{bank_ids});"
Is the sql statement above vulnerable to an injection attack, input 'bank_ids' is end user controlled.
Take as example a table designed to store a boolean value to tell if a user is admin or not (might not happend, but it's an example):
Table "public.users"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
------------+--------------------------------+-----------+----------+-----------------------------------+----------+--------------+-------------
id | bigint | | not null | nextval('users_id_seq'::regclass) | plain | |
name | character varying | | | | extended | |
admin | boolean | | | | plain | |
bank_id | integer | | | | plain | |
If you receive something like this:
'1) or id IN (select id from users where admin = true'
And that's interpolated afterward, then the select clause asking for the admin users will retrieve data that otherwise wouldn't appear. The query would be executed as it's built:
select * from users where bank_id IN (1) or id IN (select id from users where admin = true)
Is better for you to rely on the ORM you have at hand and leave it to do the sanitization and proper bindings for you (it's one of the reasons why those tools exist). Using ActiveRecord for example would bind the passed values for you, without having to do much:
User.where(bank_id: '1) or id IN (select id from users where admin = true')
# ... SELECT "users".* FROM "users" WHERE "users"."bank_id" = $1 [["bank_id", 1]]
I'm looking for some guidance in the best way to store user specific data in an SQL database. I'm a little new to SQL so I'm hoping this is a fairly easy concept for those familiar.
I've been reading about normalisation and other good practices as I'm aware that setting a good foundation for the database is crucial and hard to change later.
I think an easy way to explain my scenario is this:
Each website user can choose to create one or more "projects".
Within each project a user will set an "object". This object can be created by the user or it can be chosen from a list of objects which have been created by other users.
Each object has a variable number of settings. Let's say an object could have between 5 - 25 settings. Each setting could simply be an integer value between 0 - 100.
Originally I thought about doing it this way:
Project Table
+-----------+-------------+------+---------+----------+---------+----------+------+--------+
| ProjectID | ProjectName | User | Object1 | Object2 | SetID | Notes | Date | Photo |
+-----------+-------------+------+---------+----------+---------+----------+------+--------+
| PID0001 | My Project | Bob | OBJ0001 | OBJ00056 | SID0045 | my notes | | |
+-----------+-------------+------+---------+----------+---------+----------+------+--------+
Each user can create a project and reference different objects and object settings profiles within that project.
Object Table
+---------+------------+--------+---------+-------+--------+----------+-------+-------+---------+---------+--------+
| ObjID | ObjName | ObjVer | Date | User | Set1ID | Set1Name | Set1X | Set1Y | Set1Min | Set1Max | Set2ID |
+---------+------------+--------+---------+-------+--------+----------+-------+-------+---------+---------+--------+
| OBJ0001 | My Object | Bob | | Bob | S00013 | Volts | 12 | 52 | 1 | 80 | S00032 |
+---------+------------+--------+---------+-------+--------+----------+-------+-------+---------+---------+--------+
This table would define all the configurable settings for the object. It could range from 1 settings to 25 settings. In this example, each setting the user adds to the object would have 6 parameters such as min/max allowed values, name, id etc.
If I do it this way, I would end up with over 100 columns many of which could be empty...
Object Settings Table
+---------+-------------+---------+------------+------+---------+---------+---------+
| SetID | Setname | ObjID | Date | User | Set1Val | Set2Val | Set3Val |
+---------+-------------+---------+------------+------+---------+---------+---------+
| SID0045 | My Settings | OBJ0001 | 12-12-2017 | Bob | 12 | 32 | 98 |
+---------+-------------+---------+------------+------+---------+---------+---------+
In this table, each row would define a user's settings profile for that object - basically just the value for the settings which were defined in the object table. Each user could have a different set of settings for the same object when it's used in their project.
So, the above method seems bad to me. It makes sense in my head but the number of columns will get out of control when allowing multiple settings.
I suppose the better way of doing this would be to go vertical by adding a row for each setting or setting column but I'm just not sure how this would look. How can I structure it this way while still allowing the "sharing" of objects between user projects?
I have the following table "texts"
+---------+-------------+-------------+-----------+--------------------+
| txt_id | txt_lang_id | txt_section | txt_code | txt_value |
+---------+-------------+-------------+-----------+--------------------+
| 1 | 1 | home | txt_title | Home |
| 2 | 1 | home | txt_btn | I'm a button |
| 3 | 1 | home | txt_welc | Welcome to home |
etc...
I have multiple databases, one for each company, and a master database where the texts are created, besides, in each company, the administrator can customize your texts.
My idea is to create a query that inserts the new texts created in each database, and if it already exists to update the value.
It is possible to make the query INSERT INTO ... ON DUPLICATE KEY UPDATE Have several conditions like txt_lang_id = 1 AND txt_section = 'home' AND txt_code = 'txt_title' SET txt_value = 'New home'
My idea is to be that way, because the same function would use it for other tables, such as configuration, which is a table that starts empty, and is populated as the administrator of company changes the default options, so the auto id is not always in the same order for all companies.
It is possible to do something like this, or rather I look for the way that the rows are always in the same order. Thanks.
You can use UPDATE with CASE, e.g.:
INSERT INTO ... ON DUPLICATE KEY UPDATE txt_value =
(CASE WHEN txt_lang_id = 1 AND txt_section = 'home'
AND txt_code = 'txt_title' THEN 'New home' else txt_value end);
Here's the SQL Fiddle.
I got a problem with selecting boolean types stored as BIT with MySQL. I know that I can get bit values shown in a sensible with with custom queries like with SELECT CAST(1=1 AS SIGNED INTEGER) or with SELECT BOOLFIELD + 0 ...
However, is there any way to get our booleans shown in a sensible way with command line client with queries like SELECT * FROM TABLE ?
UPDATE : At the moment I see only space in the results Example:
mysql> SELECT distinct foo, foo + 0 from table
+------+-------+
| foo | foo_0 |
+------+-------+
| | 0 | <-- Only space
| | 1 | <-- Space, one space less
+------+-------+
With some googling, I found some (maybe related) bugs from MySQL bug DB (http://bugs.mysql.com/bug.php?id=28422, http://bugs.mysql.com/bug.php?id=43670) but not answer or fix?
To store booleans, one really ought to use MySQL's BOOLEAN type (which is an alias for TINYINT(1), given that MySQL doesn't have real boolean types): 0 represents false and non-zero represents true.
Whilst it might feel like storing a boolean in a byte is more wasteful than in a BIT(1) column, one must remember that a few saved bits will translate into more bit operations for the CPU on data storage & retrieval; and I'm unsure whether most storage engines pad BIT columns to the next byte boundary anyway.
If you insist on using BIT type columns, you should be aware that they are returned as binary strings. The MySQL command line client (stupidly) attempts to render binary strings as textual (by applying its default character set), which is what causes the behaviour that you observe—there's no way to avoid this (other than to manipulate the field in the select list in order that it as returned as something other than a binary string, as you are already doing).
However, if you also insist on using SELECT * (which is bad practice, albeit somewhat more understandable from the command line client), you might consider defining a view in which the manipulation is performed and then SELECT from that. For example:
CREATE VIEW my_view AS SELECT foo + 0 AS foo, bar FROM my_table;
Then one could do:
SELECT * FROM my_view WHERE foo = 1 AND bar = 'wibble';
A BIT ugly, but maybe some workaround: CASE WHEN ... THEN ... END
Instead of
> select
guid,
consumed,
confirmed
from Account
where customerId = 'xxxx48' and name between xxxx and xxxx;
+--------------------------------------+----------+-----------+
| guid | consumed | confirmed |
+--------------------------------------+----------+-----------+
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | | |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | | |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | | |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | | |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | | |
+--------------------------------------+----------+-----------+
One could do:
> select
guid,
case when consumed then '1' when not consumed then '0' end as been_consumed,
case when confirmed then '1' when not confirmed then '0' end as been_confirmed
from Account
where customerId = 'xxxx48' and name between xxxx and xxxx;
+--------------------------------------+---------------+----------------+
| guid | been_consumed | been_confirmed |
+--------------------------------------+---------------+----------------+
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 1 | 1 |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 1 | 0 |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 1 | 0 |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 1 | 1 |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 1 | 0 |
+--------------------------------------+---------------+----------------+