I have a table with 2 columns, one column with Alphabetic character and other column with value. Example
A 1
B 2
C 3
D 4
E 5
Now I would like to get the sum of all digits corresponding to characters containing in a string.
Like BAD = (2+1+4) = 7
Please suggest how this can be done in mysql (sql/procedure)
You can use the following solution:
I used the following to setup the table with the characters and their numeric values:
-- create the table for char values.
CREATE TABLE charValues (
charItem VARCHAR(1),
charValue INT
);
-- insert the values to the table.
INSERT INTO charValues VALUES
('A', 1),
('B', 2),
('C', 3),
('D', 4),
('E', 5);
To get the count of each character on your value, you can use the following FUNCTION (in this case named getCharCount). This FUNCTION was created on the following solution and can be used in this case to get the count of each character:
-- function to count the count of a character.
CREATE FUNCTION getCharCount (colValue VARCHAR(255), searchValue CHAR(1))
RETURNS INT DETERMINISTIC
RETURN (CHAR_LENGTH(colValue) - CHAR_LENGTH(REPLACE(colValue, searchValue, '')));
Now you can add a second FUNCTION to get the SUM of the value:
DELIMITER //
CREATE FUNCTION getStrSum (colValue VARCHAR(255))
RETURNS INT NO SQL
BEGIN
DECLARE retVal INT;
SELECT SUM(getCharCount(colValue, charItem) * charValue) INTO retVal FROM charValues;
RETURN retVal;
END //
Now you can use the following SELECT statement to get the calculated result based on table charValues. The functions can be used on the whole database like this:
SELECT getStrSum('BAD') -- output: 7
SELECT getStrSum('DAD') -- output: 9
Related
I try to filter data by a few numbers, cant use IN because it requires string value. How can I do this?
I tried sth like this but it doesn't work. How can I pas A FEW int values to filter?
You can create a parameter (filter) in your report that will accept numbers separated by , or some other character. That parameter will be string and it will look like this:
In SQL procedure separate those values using SPLIT_STRING function.
Here's a simple example.
CREATE TABLE #Numbers ( Num INT )
INSERT INTO #Numbers (Num) VALUES(1)
INSERT INTO #Numbers (Num) VALUES(2)
INSERT INTO #Numbers (Num) VALUES(3)
INSERT INTO #Numbers (Num) VALUES(4)
INSERT INTO #Numbers (Num) VALUES(5)
Task is to select some values from #Numbers table. Values to be selected are:
DECLARE #MyValues CHAR(100) = '1, 3, 5, 7'
In your example #MyValues is report parameter.
Those values will be separated by:
DECLARE #Separator CHAR = ','
Next step is to separate #MyValues and store them:
CREATE TABLE #SplitValues ( NumValues INT )
INSERT INTO #SplitValues
SELECT TRIM(Value) FROM STRING_SPLIT(#MyValues, #Separator)
Last step is to select #MyValues from #Numbers table:
SELECT * FROM #Numbers
WHERE
Num IN (SELECT * FROM #SplitValues)
Instead of using #SplitValues table there is an option of using SELECT TRIM(Value) FROM STRING_SPLIT(#MyValues, #Separator) directly in the last select, however, that way functions TRIM and SPLIT_STRING are called for every row in #Numbers table, which is "heavier" to execute.
Finally, instead of a string parameter, you can create a drop-down checkbox list and pass its values the same way, as a string that contains numbers separated by coma.
I have to sort an alphanumeric value containing some special characters in sql server, I have tried several order by clause but it is not giving the desired output( It is giving the output as 1,10,100 than 101 it should be 1,2,3..100 )
I have tried ordering by alphabets and number at same time by split but it didn't worked.
Here my solution. The first, I create a function that gets number from the string. And then sort this number.
USE tempdb
GO
CREATE TABLE MyTable (ID INT, Col1 VARCHAR(100))
GO
-----
INSERT INTO MyTable (ID, Col1)
SELECT 1, 'CBSFBE20151202000017_000_1.tif'
UNION ALL
SELECT 2, 'CBSFBE20151202000017_000_10.tif'
UNION ALL
SELECT 3, 'CBSFBE20151202000017_000_2.tif'
UNION ALL
SELECT 4, 'CBSFBE20151202000017_000_3.tif'
UNION ALL
SELECT 5, 'CBSFBE20151202000017_000_11.tif'
-----
CREATE FUNCTION dbo.fnGetNumberFromString (#strInput VARCHAR(255))
RETURNS VARCHAR(255)
AS
BEGIN
DECLARE #intNumber int
SET #intNumber = PATINDEX('%[^0-9]%', #strInput)
WHILE #intNumber > 0
BEGIN
SET #strInput = STUFF(#strInput, #intNumber, 1, '')
SET #intNumber = PATINDEX('%[^0-9]%', #strInput)
END
RETURN ISNULL(#strInput,0)
END
GO
-----
SELECT *, dbo.fnGetNumberFromString(Col1) AS Number
FROM MyTable
order by CAST(dbo.fnGetNumberFromString(Col1) AS float), Col1
After reading this question, I'm trying to convert some SQL from MySQL to PostgreSQL. Thus I need variable assignation:
INSERT INTO main_categorie (description) VALUES ('Verbe normal');
SET #PRONOMINAL := SELECT LAST_INSERT_ID();
INSERT INTO main_mot (txt,im,date_c,date_v_d,date_l)
VALUES ('je m''abaisse',1,NOW(),NOW(),NOW());
SET #verbe_149 = SELECT LAST_INSERT_ID();
INSERT INTO main_motcategorie (mot_id,categorie_id) VALUES (#verbe_149,#PRONOMINAL);
How would you do this with PostgreSQL? No useful sample in the documentation of v9 and v8 (almost the same).
NB: I dont want to use a stored procedure like here, I just want "raw sql" so I can inject it through CLI interface.
There are no variables in Postgres SQL (you can use variables only in procedural languages).
Use RETURNING in WITH query:
WITH insert_cat AS (
INSERT INTO main_categorie (description)
VALUES ('Verbe normal')
RETURNING id
),
insert_mot AS (
INSERT INTO main_mot (txt,im,date_c,date_v_d,date_l)
VALUES ('je m''abaisse',1,NOW(),NOW(),NOW())
RETURNING id
)
INSERT INTO main_motcategorie (mot_id,categorie_id)
SELECT m.id, c.id
FROM insert_mot m, insert_cat c;
As an alternative, you can use custom configuration parameters in the way described in this post.
Create two functions:
create or replace function set_var (name text, value text)
returns void language plpgsql as $$
begin
execute format('set mysql.%s to %s', name, value);
end $$;
create or replace function get_var (name text)
returns text language plpgsql as $$
declare
rslt text;
begin
execute format('select current_setting(''mysql.%s'')', name) into rslt;
return rslt;
end $$;
With the functions you can simulate variables, like in the example:
INSERT INTO main_categorie (description)
VALUES ('Verbe normal');
SELECT set_var('PRONOMINAL', (SELECT currval('main_categorie_id_seq')::text));
INSERT INTO main_mot (txt,im,date_c,date_v_d,date_l)
VALUES ('je m''abaisse',1,NOW(),NOW(),NOW());
SELECT set_var('verbe_149', (SELECT currval('main_mot_id_seq')::text));
INSERT INTO main_motcategorie (mot_id,categorie_id)
SELECT get_var('verbe_149')::int, get_var('PRONOMINAL')::int;
This is certainly not an example of good code.
Particularly the necessity of casting is troublesome.
However, the conversion can be done semi-automatically.
You can run PostgreSQL scripts outside of a function using the do construct. Here's an example with Donald Ducks' nephews. First the nephew will be added to the nephew table, and then we'll add a baseball cap using the newly inserted nephew's id.
First, create two tables for nephews and baseball caps:
drop table if exists nephew;
drop table if exists cap;
create table nephew (id serial primary key, name text);
create table cap (id serial, nephewid bigint, color text);
Now add the first nephew:
do $$declare
newid bigint;
begin
insert into nephew (name) values ('Huey') returning id into newid;
insert into cap (nephewid, color) values (newid, 'Red');
end$$;
The returning ... into ... does in Postgres what currval does in MySQL. Huey's new id is assigned to the newid variable, and then used to insert a new row into the cap table. You can run this script just like any other SQL statement. Continue with Dewey and Louie:
do $$declare
newid bigint;
begin
insert into nephew (name) values ('Dewey') returning id into newid;
insert into nephew (name) values ('Louie') returning id into newid;
insert into cap (nephewid, color) values (newid, 'Green');
end$$;
And you end up with:
# select * from nephew;
id | name
----+-------
1 | Huey
2 | Dewey
3 | Louie
(3 rows)
# select * from cap;
id | nephewid | color
----+----------+-------
1 | 1 | Red
2 | 3 | Green
(2 rows)
See it working at SQL Fiddle.
I have some data that converts which has a 2 columns one column has IP and it contains values which are integers.I used the following function in my mysql query.Is there a function i can use to to convert my mac column which contains integers and data type is bigint to MAC address.
SELECT INET_NTOA(ip_address) AS myip,mymac
FROM table1
Assuming that you have stored the MAC address by suppressing all separators and converting the resulting HEX number into int, the conversion from this int to a human readable MAC address would be:
function int2macaddress($int) {
$hex = base_convert($int, 10, 16);
while (strlen($hex) < 12)
$hex = '0'.$hex;
return strtoupper(implode(':', str_split($hex,2)));
}
The function is taken from http://www.onurguzel.com/storing-mac-address-in-a-mysql-database/
The MySQL version for this function:
delimiter $$
create function itomac (i BIGINT)
returns char(20)
language SQL
begin
declare temp CHAR(20);
set temp = lpad (hex (i), 12, '0');
return concat (left (temp, 2),':',mid(temp,3,2),':',mid(temp,5,2),':',mid(temp,7,2),':',mid(temp,9,2),':',mid(temp,11,2));
end;
$$
delimiter ;
You can also do it directly in SQL, like this:
select
concat (left (b.mh, 2),':',mid(b.mh,3,2),':',mid(b.mh,5,2),':',mid(b.mh,7,2),':',mid(b.mh,9,2),':',mid(b.mh,11,2))
from (
select lpad (hex (a.mac_as_int), 12, '0') as mh
from (
select 1234567890 as mac_as_int
) a
) b
Just use HEX():
For a numeric argument N, HEX() returns a hexadecimal string representation of the value of N treated as a longlong (BIGINT) number.
Therefore, in your case:
SELECT INET_NTOA(ip_address) AS myip, HEX(mymac)
FROM table1
Note that this won't insert byte delimiters, such as colon characters.
I'm writing a query that selects data from one table into another, one of the columns that needs to be moved is a DECIMAL column. For reasons beyond my control, the source column can sometimes be a comma separated list of numbers. Is there an elegant sql only way to do this?
For example:
source column
10.2
5,2.1
4
Should produce a destination column
10.2
7.1
4
I'm using MySQL 4, btw.
To do this kind of non trivial string manipulations, you need to use stored procedures, which, for MySQL, only appeared 6 years ago, in version 5.0.
MySQL 4 is now very old, the latest version from branch 4.1 was 4.1.25, in 2008. It is not supported anymore. Most Linux distributions don't provide it anymore. It's really time to upgrade.
Here is a solution that works for MySQL 5.0+:
DELIMITER //
CREATE FUNCTION SUM_OF_LIST(s TEXT)
RETURNS DOUBLE
DETERMINISTIC
NO SQL
BEGIN
DECLARE res DOUBLE DEFAULT 0;
WHILE INSTR(s, ",") > 0 DO
SET res = res + SUBSTRING_INDEX(s, ",", 1);
SET s = MID(s, INSTR(s, ",") + 1);
END WHILE;
RETURN res + s;
END //
DELIMITER ;
Example:
mysql> SELECT SUM_OF_LIST("5,2.1") AS Result;
+--------+
| Result |
+--------+
| 7.1 |
+--------+
Here is a mysql function to split a string:
CREATE FUNCTION SPLIT_STR(
x VARCHAR(255),
delim VARCHAR(12),
pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
delim, '');
And u have to use it this way:
SELECT SPLIT_STR(FIELD, ',', 1) + SPLIT_STR(FIELD, ',', 2) FROM TABLE
Unfortunately mysql does not include string split functions or aggregates, so you will need to do this either in a stored procedure or on the client side.
A number table-based parse approach can be found at this SQLFiddle link. Esentially, once you have the substrings, the sum function will auto-cast the numbers. For convenience:
create table scores (id int primary key auto_increment, valueset varchar(30));
insert into scores (valueset) values ('7,6,8');
insert into scores (valueset) values ('3,2');
create table numbers (n int primary key auto_increment, stuffer varchar(3));
insert into numbers (stuffer) values (NULL);
insert into numbers (stuffer) values (NULL);
insert into numbers (stuffer) values (NULL);
insert into numbers (stuffer) values (NULL);
insert into numbers (stuffer) values (NULL);
SELECT ID, SUM(SCORE) AS SCORE
FROM (
SELECT
S.id
,SUBSTRING_INDEX(SUBSTRING_INDEX(S.valueset, ',', numbers.n),',',-1) score
, Numbers.n
FROM
numbers
JOIN scores S ON CHAR_LENGTH(S.valueset)
-CHAR_LENGTH(REPLACE(S.valueset, ',', ''))>=numbers.n-1
) Z
GROUP BY ID
;