Compare two strings according to defined values in a query - mysql

I have to compare two string fields containing letters but not alphabetically.
I want to compare them according to this order :
"J" "L" "M" "N" "P" "Q" "R" "S" "T" "H" "V" "W" "Y" "Z"
So if I compare H with T, H will be greater than T (unlike alphabetically)
And if I test if a value is greater than 'H' (> 'H') I will get all the entries containing the values ("V" "W" "Y" "Z") (again, unlike alphabetical order)
How can I achieve this in one SQL query?
Thanks

SELECT *
FROM yourtable
WHERE
FIELD(col, 'J', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'H', 'V', 'W', 'Y', 'Z') >
FIELD('H', 'J', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'H', 'V', 'W', 'Y', 'Z')
^ your value
Or also:
SELECT *
FROM yourtable
WHERE
LOCATE(col, 'JLMNPQRSTHVWYZ')>
LOCATE('H', 'JLMNPQRSTHVWYZ')
Please see fiddle here.

You can do
SELECT ... FROM ... ORDER BY yourletterfield='J' DESC, yourletterfield='L' DESC, yourletterfield='M' DESC, ...
The equality operator will evaluate to "1" when it's true, "0" when false, so this should give you the desired order.
There's actually a FIELD() function that will make this a bit less verbose. See this article for details.
SELECT ... FROM ... ORDER BY FIELD(yourletterfield, 'J', 'L', 'M', ...)

Related

The query returns wrong result when i want to find who is the shortest player in a NBA Database

I am working with a NBA script in MySQL and I have to find out who is the shortest player in database. I am using feet as measurement and after executing the query i found out that the player the query was giving me was not the right answer.
The query is
select * from players where height=(select min(height) from players);
And it gaves me:
'420', 'Carlos Arroyo', 'Florida International', ' 6-2', '202', 'G', 'Magic'
where 6-2 is the height.
Instead of giving me one of these results
'26', 'Brevin Knight', 'Stanford', '5-10', '170', 'G', 'Clippers'
'113', 'Nate Robinson', 'Washington', '5-9', '180', 'G', 'Knicks'
'182', 'Earl Boykins', 'Eastern michigan', '5-5', '133', 'G', 'Bobcats'
'372', 'Damon Stoudamire', 'Arizona', '5-10', '171', 'G', 'Spurs'
'482', 'Chucky Atkins', 'South Florida', '5-11', '185', 'G', 'Nuggets'
And if I order by height players, the result it's a bit annoying:
'Carlos Arroyo', ' 6-2'
'Shareef Abdur-Rahim', ' 6-9'
'Louis Amundson', ' 6-9'
'Brevin Knight', '5-10'
'Damon Stoudamire', '5-10'
'Chucky Atkins', '5-11'
'Earl Boykins', '5-5'
'Nate Robinson', '5-9'
'Aaron Brooks', '6-0'
'Allen Iverson', '6-0'
'Kyle Lowry', '6-0'
'Jammer Nelson', '6-0'
'Sebastian Telfair', '6-0'
'Chris Paul', '6-0'
Convert the height-string to a number which you can use for numeric comparison.
select player, height
from players
where cast(substring_index(height, '-', 1) as unsigned)*100+
cast(right(concat('0', substring_index(height, '-', -1)),2) as unsigned)
in (
select min(cast(substring_index(height, '-', 1) as unsigned)*100+
cast(right(concat('0', substring_index(height, '-', -1)),2) as unsigned))
from players
)
See dbfiddle
...
where 6-2 is the height. Instead of giving me one of these results
...
You tell that all values '5-xx' are equivalent to each other, i.e. only value before the dash is taken into account.
Also you tell that you need in only one output row, and any row of shown 5 rows matches - i.e. you do not need in secondary sorting.
If so then you may simply do
SELECT *
FROM players
ORDER BY CAST(height AS UNSIGNED) LIMIT 1

Parse data from csv file into given format using Prolog

I have the csv file that contains data as:
A B C
A - 4 5
B 8 - 6
C 2 3 -
I want to have facts in the following form:
num(a,b,4).
num(a,c,5).
num(b,a,8).
num(b,c,6).
num(c,a,2).
num(c,b,3).
There should not be facts for similar alphabets like num(a,a,-).
I am using prolog's csv_read_file as:
csv_read_file(Path, Rows, [functor(num), arity(4)]), maplist(assert, Rows).
and its giving me output as:
Rows = [num('', 'A', 'B', 'C'), num('A', -, 4, 5), num('B', 8, -, 6), num('C', 2, 3, -)]
It seems to be a basic question, but I am not able to think about condition to perform this. Any help will be highly appreciated.
As per Isabelle Newbie Answer:
Open :- csv_read_file('Path', Rows, [functor(num), arity(4)]), table_entry(Rows, Row).
header_row_entry(Header,Row,Entry):-
arg(1, Row, RowName),
functor(Header, _, Arity),
between(2,Arity,ArgIndex),
arg(ArgIndex, Header, ColumnName),
arg(ArgIndex, Row, Value),
Entry = num(RowName, ColumnName, Value),
writeln(Entry).
table_entry(Entries, Entry):-
Entries = [Header | Rows],
member(Row, Rows),
header_row_entry(Header, Row, Entry).
Now, can anyone explain how and where I should use maplist to convert the rows in form of facts (neglect filtering of '-' and lowercase for now) so that when I query:
?-num(A,B,X).
I should get:
X=4
Next task is, I want to implement depth first search algorithm on it. Any details regarding this will be highly appreciated.
Consider a table header num('', 'A', 'B', 'C') and a row in the table num('B', 8, -, 6). From this you want to compute a table entry identified by the row's name, which here is 'B', and by a column name: the column name being 'A' for the first value (8), 'B' for the second (-), 'C' for the third (6).
Here's a simple way to do this, involving some typing and the obligatory copy-and-paste errors:
header_row_entry(Header, Row, Entry) :-
Header = num('', ColumnName, _, _),
Row = num(RowName, Value, _, _),
Entry = num(RowName, ColumnName, Value).
header_row_entry(Header, Row, Entry) :-
Header = num('', _, ColumnName, _),
Row = num(RowName, _, Value, _),
Entry = num(RowName, ColumnName, Value).
header_row_entry(Header, Row, Entry) :-
Header = num('', _, _, ColumnName),
Row = num(RowName, _, _, Value),
Entry = num(RowName, ColumnName, Value).
This enumerates all the entries in a row on backtracking:
?- Header = num('', 'A', 'B', 'C'), Row = num('B', 8, -, 6),
header_row_entry(Header, Row, Entry).
Header = num('', 'A', 'B', 'C'),
Row = num('B', 8, -, 6),
Entry = num('B', 'A', 8) ;
Header = num('', 'A', 'B', 'C'),
Row = num('B', 8, -, 6),
Entry = num('B', 'B', -) ;
Header = num('', 'A', 'B', 'C'),
Row = num('B', 8, -, 6),
Entry = num('B', 'C', 6).
To enumerate all the entries in an entire table, it remains to enumerate all rows, then enumerate row entries as above. Here this is:
table_entry(Entries, Entry) :-
Entries = [Header | Rows],
member(Row, Rows),
header_row_entry(Header, Row, Entry).
And now, given your table:
?- Table = [num('', 'A', 'B', 'C'), num('A', -, 4, 5), num('B', 8, -, 6), num('C', 2, 3, -)], table_entry(Table, Entry).
Table = [num('', 'A', 'B', 'C'), num('A', -, 4, 5), num('B', 8, -, 6), num('C', 2, 3, -)],
Entry = num('A', 'A', -) ;
Table = [num('', 'A', 'B', 'C'), num('A', -, 4, 5), num('B', 8, -, 6), num('C', 2, 3, -)],
Entry = num('A', 'B', 4) ;
Table = [num('', 'A', 'B', 'C'), num('A', -, 4, 5), num('B', 8, -, 6), num('C', 2, 3, -)],
Entry = num('A', 'C', 5) ;
Table = [num('', 'A', 'B', 'C'), num('A', -, 4, 5), num('B', 8, -, 6), num('C', 2, 3, -)],
Entry = num('B', 'A', 8) ;
Table = [num('', 'A', 'B', 'C'), num('A', -, 4, 5), num('B', 8, -, 6), num('C', 2, 3, -)],
Entry = num('B', 'B', -) . % etc.
Depending on what you want exactly, it remains to lowercase the row and column names (the irritatingly named downcase_atom in SWI-Prolog, for example) and filter out the - entries. You can then assert the entries using a failure-driven loop or by collecting all of them using findall and asserting using maplist.
Now that we have a working solution, we might want header_row_entry to be a bit nicer. We can use arg/3 to capture more explicitly that we are trying to pair a column name and a value that are at the same argument position in their respective header and row terms:
header_row_entry(Header, Row, Entry) :-
arg(1, Row, RowName),
functor(Header, _, Arity),
between(2, Arity, ArgIndex),
arg(ArgIndex, Header, ColumnName),
arg(ArgIndex, Row, Value),
Entry = num(RowName, ColumnName, Value).
This is shorter than the above and applicable to any number of columns in the table.

Multi row insert using Knex.js

Am trying to build an multi-row insert query using Knex.js
My post request contains a variable which is formatted in the following format : [{addon_name:'sugar'},{addon_name:'milk'}]
My DB table has only one column namely addon_name
My knex query in my node application goes as follows
knex(`<table_name>`).insert(req.body.`<param_name>`))
expected op
insert into `<tablename>`(`addon_name`) values (sugar), (milk);
but the code dosn't work. Any comments ?
Error Details
{ [Error: insert into `table_name` (`0`, `1`, `10`, `11`, `12`, `13`, `14`, `15`, `16`, `17`, `18`, `19`, `2`, `20`, `21`, `22`, `23`, `24`, `25`, `26`, `27`, `28`, `29`, `3`, `30`, `31`, `32`, `33`, `34`, `35`, `36`, `37`, `38`, `39`, `4`, `40`, `41`, `5`, `6`, `7`, `8`, `9`) values ('[', '{', 'm', 'e', ':', '\'', 's', 'u', 'g', 'a', 'r', '\'', 'a', '}', ',', '{', 'a', 'd', 'd', 'o', 'n', '_', 'n', 'd', 'a', 'm', 'e', ':', '\'', 'm', 'i', 'l', 'k', '\'', 'd', '}', ']', 'o', 'n', '_', 'n', 'a') - ER_BAD_FIELD_ERROR: Unknown column '0' in 'field list']
code: 'ER_BAD_FIELD_ERROR',
errno: 1054,
sqlState: '42S22',
index: 0 }
Though this is an old question, I am replying here just for others who stumble upon this.
Knex now supports multi-row inserts like this:
knex('coords').insert([{x: 20}, {y: 30}, {x: 10, y: 20}])
outputs:
insert into `coords` (`x`, `y`) values (20, DEFAULT), (DEFAULT, 30), (10, 20)
There's also the batchInsert utility will inserts a batch of rows wrapped inside a transaction.
req.body.<param_name> is always a string. Most probably this will work for you:
knex(table_name).insert(JSON.parse(req.body.param_name)));
What you are seeing in your error is Knex treating the string as an array of chars, trying to push it to the table.
In the error, the following:
values ('[', '{', 'm', 'e', ':', '\'', 's', ...
Is actually your string being broken down: [{me:\'s....
Thanks. I changed the structure of my input in post method, to an comma separated string. That way it gets easier to parse the input and model it the way I need.
post method input : "milk,sugar"
code
//Knex accepts multi row insert in the following format [{},{}] => we need to
//model our input that way
var parsedValues = [];
try {
var arr = req.body.addons.split(',');
}catch(err){
return res.send({ "Message": "405" }); // Data not sent in proper format
}
for (var i in arr) {
parsedValues.push({addon_name: arr[i]});
}
console.log(parsedValues);
knex(`<table_name>`).insert(parsedValues).then(function (rows){
console.log(rows);
return res.send({ "Message": "777" }); // Operation Success
}).catch(function (err){
console.log(err)
return res.send({ "Message": "403" }); // PK / FK Violation
});
You can use batch insert
DB.transaction(async (t: Knex.Transaction) => {
return await t
.batchInsert("addon_name", addon_nameRecords)
.returning("id");
});

Is there an equivalent to "tr" within SQL?

To remind you, tr
reads a byte stream from its standard input and writes the result to
the standard output. As arguments, it takes two sets of characters
(generally of the same length), and replaces occurrences of the
characters in the first set with the corresponding elements from the
second set. -- Wikipedia
I need to this within the context of an UPDATE statement and, ideally, without doing 26 nested REPLACE function calls.
EDIT:
For you nosy-Parkers who just have to know what I'm doing: I want to make the in-database equivalent of upsidedowntext.com. Right now, I do this:
SELECT
REVERSE(
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(UPPER(value),
'A', 'ɐ'),
'B', 'q'),
'C', 'ɔ'),
'D', 'p'),
'E', 'ǝ'),
'F', 'ɟ'),
'G', 'b'),
'H', 'ɥ'),
'I', 'ı'),
'J', 'ظ'),
'K', 'ʞ'),
'L', 'ן'),
'M', 'ɯ'),
'N', 'u'),
'O', 'o'),
'P', 'd'),
'Q', 'b'),
'R', 'ɹ'),
'S', 's'),
'T', 'ʇ'),
'U', 'n'),
'V', 'ʌ'),
'W', 'ʍ'),
'X', 'x'),
'Y', 'ʎ'),
'Z', 'z')) from table;

SQL Server : how does the Replace function work as its acting strange for me

I am 'randomising' some strings in a SQL Server table to do a primitive encryption on them.
I have a nested SQL replace function around 35 times (A-Z,1-9) that basically takes every letter in the alphabet and number and replaces it with another letter or number. example of which would be
Replace(Replace(Replace('a', 'c'), 'b', 'a'), 'c', 'b')
I figured that the replace function would go though a string like 'abc' and replace everything once and stop - 'cab'. It doesn't!
It seems to want to change some characters again resulting in 'abc'->'cab'->'ccb'.
This is fine except if I have another string called 'aac' this could result in duplicate string and I lose traceability back to original.
Can anyone explain how I could stop REPLACE() partially going back over my string?
SELECT * INTO example_temp FROM example;
Update KAP_db.dbo.example_temp Set col1 = replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(‌​replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(
replace‌​(replace(replace(replace(replace(replace(replace(replace(replace(replace(
col1, 'A', 'N'),'B', 'O'), 'C', 'P'), 'D', 'Q'), 'E', 'R'), 'F', 'S'), 'G', 'T'),
'H', 'U'), 'I', 'V'), 'J', 'W'), 'K', 'X'), 'L', 'Y'), 'M', 'Z'), 'O', 'A'), 'P', 'B'),
'Q', 'C'), 'R', 'D'),'S', 'E'),'T', 'E'),'U', 'E'),'V', 'F'),'W', 'G'),'X', 'H'),
'Y', 'I'),'Z', 'J'), '1', '9'),'2','8'),'3','7'),'4','6'),'5','5'),'6','4'),'7','3'),
'8','2'),'9','1'),' ','');
The above results in '8EVHUAB' and '8EVHHAB' both outputting '2DFEENA'
Update -------------------------------------------------------------------
Ok i have redone the code and so far have:
DECLARE #Input AS VarChar(1000)
DECLARE #i AS TinyInt
Declare #Substring AS VarChar(1000)
Declare #Prestring AS VarChar(1000)
Declare #Poststring AS VarChar(1000)
Select #Input='ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789'
SELECT #i = 1
Select #Substring ='na'
WHILE #i <= LEN(#Input) BEGIN
Select #Prestring = SUBSTRING(#Input,-1,#i)
Select #Poststring = SUBSTRING(#Input,#i+1,LEN(#Input))
SELECT #Substring = replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace
(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace
(SUBSTRING(#Input,#i,1), 'A', 'N'),'B', 'O'), 'C', 'P'), 'D', 'Q'), 'E', 'R'), 'F', 'S'), 'G', 'T'), 'H', 'U'), 'I', 'V'), 'J', 'W'), 'K', 'X'), 'L', 'Y'), 'M', 'Z'), 'N', 'A'), '0', 'B'), 'P', 'C')
, 'Q', 'D'),'R', 'E'),'S', 'E'),'T', 'E'),'U', 'F'),'V', 'G'),'W', 'H'),'X', 'I'),'Y', 'J'), '1', '9'),'2','8'),'3','7'),'4','6'),'5','5'),'6','4'),'7','3'),'8','2'),'9','1'),' ','')
Select #Input = #Prestring + #Substring + #Poststring
SELECT #i = #i + 1
print 'END
'
END
This doesnt work correctly though, the code does not execute as its written, any suggestions?
Why you're seeing this: replace is a function; all it knows are its arguments. replace(replace('aba', 'a', 'b'), 'b', 'a') is absolutely equivalent to replace('bbb', 'b', 'a'), because the outer replace has no way of knowing that its first argument was created by a different call to replace. Does that make sense?
You can think of it just like a function in algebra. If we define f(x) = x2, then f(f(2)) = f(22) = f(4) = 42 = 16. There's no way to tell f to behave differently when its argument is f(2) from when its argument is 4, because f(2) is 4.
Similarly, replace('aba', 'a', 'b') is 'bbb', so there's no way to tell replace to behave differently when its first argument is replace('aba', 'a', 'b') from when its first argument is 'bbb'.
(This is usually true in computer science. Functions in computer science aren't always like functions in algebra — for example, they frequently actually do things, rather than just returning a value — but it's usually the case that they receive arguments as values, or as opaque references to values, and have no way of knowing where they came from or how they were constructed.)
How to address this: I don't think there's any very clean way to do this. Gordon Linoff suggested that you could use intermediate placeholder characters (specifically — lowercase letters) that don't exist in the initial string and don't exist in the final string, so that you can safely replace them without worrying about interference; and I think that's probably the best approach.
Your results are not surprising, since each replace is returning the string to the next level. There is no way to distinguish between the original character value and the replaced value, when they are the same character.
If you were only working with alpha characters you could do the following.
Change the collation of the original string.
Upper case the string
Replace the upper case letters with the lower case
Lower case the entire string at the end (should be redundant)
Unfortunately, I can't think of an analog for numbers that would work the same way.
Here is a link to a site that has code for the function http://www.dbforums.com/microsoft-sql-server/1216565-oracle-translate-function-equivalent-sql-server.html. The equivalent function in Oracle is called translate.
The Replace() function simply performs the operation and returns. It doesn't keep state to the next Replace(). It doesn't prevent a later invocation from replacing the characters you previously replaced. To cycle characters around, you have to have an additional "placeholder" value, and then take care to not replace a character that was already change from something else.
First, let me show you an analogy:
There are three buckets full of an equal number of marbles. The buckets are labeled "A", "B", and "C". You must perform the following instructions:
Pour all marbles from A into C.
Pour all marbles from B into A.
Pour all marbles from C into B.
What result would you expect to have? The answer is: an empty bucket C, and B having twice the number of marbles as are in A.
If you want to preserve the marbles in their original counts, you have to have four containers so that you don't mix the marbles while moving them:
Pour all marbles from C into X.
Pour all marbles from A into C.
Pour all marbles from B into A.
Pour all marbles from X into B. (rather than from C--which already has A's marbles)
Now you have the results you expected, and can discard the empty bucket X.
Try this expression and see if it gives what you want:
Replace(Replace(Replace(Replace('c', char(1)), 'a', 'c'), 'b', 'a'), char(1), 'b')