Issue with simple division in SQL Server - sql-server-2008

I must be a total idiot or something. I'm using Microsoft SQL Server 2008. I can't do simple division. SELECT 200/600 returns a big fat goose egg (0.00). Yet if I do 600/200 it returns 3. The only thing I can think of is some server setting. I'm feeling pretty darn stupid here. Can somebody please help?

The numbers you are using are being interpreted as integers, hence values you might not normally expect.
Try this...
select 200.0/600.0
and you'll see that SQL Server treats the numbers as floats and therefore gives you the result you want.
Alternatively you could try
select cast (200 as float) / cast (600 as float)
And you'd get the same result - all I've done here is to explicitly cast the values as floats.

Related

M expression for SSIS equivalent

I've just started exploring DAX on PowerBI; so please excuse if this query sounds too novice to expert users. DAX functions are too 'different' if coming from a SQL background, hence the query.
In SSIS I'm using a function to replace values in a column based on a string (more so, an error in the value). I'm using the below to do the job easily:
Column2 = SUBSTRING([Column1],1,FINDSTRING([Column1],";#",1) - 1)
Even after looking at the Text functions on Microsoft help page.
for almost an hour trying to understand; I couldn't for some reason.
Any ideas?
An analogous expression in M would be
Text.Middle([Column1], 1, Text.PositionOf([Column1], ";#") - 1)
But you could also use Text.Start instead since you're starting at 1 or make it even simpler with Text.BeforeDelimiter:
Text.BeforeDelimiter([Column1], ";#")
In DAX, you'd use MID/LEFT instead of Text.Start/Text.Middle and FIND or SEARCH (depending on if you need case-sensitivity or not) instead of Text.PositionOf.
LEFT ( [Column1], SEARCH ( ";#", [Column1] ) - 1 )
Either way, the logic is nearly identical but you just have different function names.

Common Table Expressions -- Using a Variable in the Predicate

I've written a common table expression to return hierarchical information and it seems to work without issue if I hard code a value into the WHERE statement. If I use a variable (even if the variable contains the same information as the hard coded value), I get the error The maximum recursion 100 has been exhausted before statement completion.
This is easier shown with a simple example (note, I haven't included the actual code for the CTE just to keep things clearer. If you think it's useful, I can certainly add it).
This Works
WITH Blder
AS
(-- CODE IS HERE )
SELECT
*
FROM Blder as b
WHERE b.PartNo = 'ABCDE';
This throws the Max Recursion Error
DECLARE #part CHAR(25);
SET #part = 'ABCDE'
WITH Blder
AS
(-- CODE IS HERE )
SELECT
*
FROM Blder as b
WHERE b.PartNo = #part;
Am I missing something silly? Or does the SQL engine handle hardcoded values and parameter values differently in this type of scenario?
Kindly put semicolon at the end of your variable assignment statement
SET #part ='ABCDE';
Your SELECT statement is written incorrectly: the SQL Server Query Optimizer is able to optimize away the potential cycle if fed the literal string, but not when it's fed a variable, which uses the plan that developed from the statistics.
SQL Server 2016 improved on the Query Optimizer, so if you could migrate your DB to SQL Server 2016 or newer, either with the DB compatibility level set to 130 or higher (for SQL Server 2016 and up), or have it kept at 100 (for SQL Server 2008) but with OPTION (USE HINT ('ENABLE_QUERY_OPTIMIZER_HOTFIXES')) added to the bottom of your SELECT statement, you should get the desired result without the max recursion error.
If you are stuck on SQL Server 2008, you could also add OPTION (RECOMPILE) to the bottom of your SELECT statement to create an ad hoc query plan that would be similar to the one that worked correctly.

Calculating Conversion Rate In MySQL

I'm trying to calculate the conversion rate of clicks and unique visitors for local analytic part of a website. MySQL 5.1.73, appears to not like my query. I'm not sure if the sources I'm getting are using deprecated syntax, or I'm simply not asking the correct question in Google.
SELECT
(SUM(click1) DIV SUM(unique) * 100) /* <<<< Synrax Error Here */
FROM
stats_clicks
WHERE
aid = 10050 AND
timestamp_local BETWEEN '2014/01/01' AND '2015/12/01'
Sorry if this is a very beginner-isk question. A lot of my resources are not working in this case.
unique is a reserved word in SQL. The best idea would probably be to rename it to unique_clicks or something down those lines. If that is not possible, you can escape it with forward quotes (`s).
Additionally, while div is perfectly legal syntax in MySQL, it performs integer division. Chances are you meant to use floating point division, which can simply be done with the / operator:
SELECT (SUM(click1) / SUM(`unique`) * 100)
Use
(100 * SUM(click1) / SUM(`unique`))

MySQL Syntax error for 5.6.17_1

I have MySQL 5.6.17_1 and have query that is used for 5.1.xx
select
schtermid,idfptnsubid,d.idfptnid,idflinksetid,
cast(count(distinct cthr) as real)/cast(count(distinct s.schid) as real)*100 as ctr, cast(sum(status) as real)/cast(count(*) as real)*100 as pfiled,
count(distinct s.schid) as schcount
from source.kdm_session as
This complains
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near
'real)/cast(count(distinct s.schid) as real)*100 as ctr, cast(sum(status) as' at line 3
Which part is wrong? What should I change to get the same thing to happen?
As per the docs, real is not a valid type:
The type for the result can be one of the following values:
BINARY[(N)]
CHAR[(N)]
DATE
DATETIME
DECIMAL[(M[,D])]
SIGNED [INTEGER]
TIME
UNSIGNED [INTEGER]
Try this for your calcs:
(count(distinct cthr) * 1.0)/(count(distinct s.schid) * 1.0)*100 as ctr,
(sum(status) * 1.0)/(count(*) * 1.0)*100 as pfiled,
This is rather a mess - you are mixing up the arguments and inventing types. You're also trying to use AS both as a seperator within a call to CAST() and as an alias operator. Since its meaning is contextual it's good practice not to mix and match in the same query.
Formatting part of your query...
cast(
count(distinct cthr) as real)
/ cast(
count(distinct s.schid) as real
)*100 as ctr
, cast(sum(status) as real)
/cast(count(*) as real)*100 as pfiled
Sorry - but this is so messed up I haven't a clue what you are trying to do here. You seem to be trying the cast the result of a calulation to a type defined by the result of another calculation. Since the can't all have the same alias I guess you must think that 'real' is a type in MySQL (it isn't). Even if you meant a floatling point number - this is just silly - the result of a count is always an integer. You don't even have the same number of opening and closing brackets.
In addition to NOT using 'AS' within CAST(), and using the valid MySQL types, if you formatted your quesry better and provided examples of inputs and outputs we might have a chance at helping you.

MySQL insert to bit(1) column via ODBC 5.2

I've searched and can't seem to find quite what I'm looking for.
I'm running a PL/SQL script in Oracle, and attempting to insert records into a table in MySQL via database link using MySQL ODBC 5.2 Unicode Driver.
The link works fine, I can do complex queries in Oracle using it, and do various inserts and updates on records there.
Where it fails is in trying to insert a record into a MySQL table that has a column of type bit(1).
It is basically a cursor for loop, with the insert statement looking something like:
INSERT INTO "app_user"#mobileapi (USERNAME, VERSION, ACCOUNT_EXPIRED, ACCOUNT_LOCKED, PASSWD, PASSWORD_EXPIRED)
VALUES (CU_rec.USERNAME, CU_rec.VERSION, CU_rec.ACCOUNT_EXPIRED, CU_rec.ACCOUNT_LOCKED, CU_rec.PASSWD, CU_rec.PASSWORD_EXPIRED)
Some of the target columns, like ACCOUNT_EXPIRED, ACCOUNT_LOCKED, etc. are the bit(1) columns in MySQL. Given that I can convert the data types in the cursor CU_rec to pretty much anything I want in Oracle, how can I get them inserted into the target? I've tried everything I can think of, and I just keep getting:
Error report:
ORA-28500: connection from ORACLE to a non-Oracle system returned this message:
[MySQL][ODBC 5.2(w) Driver][mysqld-5.6.10]Data too long for column 'ACCOUNT_EXPIRED' at row 1 {HY000,NativeErr = 1406}
ORA-02063: preceding 2 lines from MOBILEAPI
ORA-06512: at line 44
28500. 00000 - "connection from ORACLE to a non-Oracle system returned this message:"
*Cause: The cause is explained in the forwarded message.
*Action: See the non-Oracle system's documentation of the forwarded
message.
Any help at all would be greatly appreciated.
Your problem is Oracle's default datatype conversion over ODBC; according to their own documentation they convert SQL_BINARY to a raw. Although not directly related, Oracle's comparison of MySQL and Oracle within SQL Developer also alludes to the fact that the automatic conversion from a MySQL bit is to an Oracle raw.
Extremely confusingly, MySQL's documentation indicates that a bit is converted to a SQL_BIT or a SQL_CHAR, which implies that it may work in the other direction1.
According to Microsoft's ODBC docs you should, theoretically, be able to use the CONVERT() function to transform this into a character, which should, theoretically, be translatable by MySQL.
insert into some_table#some_db (bit_col)
values( {fn convert(some_col, SQL_CHAR)} );
Failing that there's another couple of options, but it does depend on what you're attempting to insert into the MySQL database from Oracle and what the datatype is in Oracle. For instance you could use the Oracle CAST() function to convert between datatypes. For instance, the following would convert an integer to a binary double.
select cast(1 as binary_double) from dual
Unfortunately, you can't cast an integer to a raw, only a character or a rowid, so in order to convert to a raw you'd have to do the following:
select cast(to_char(1) as raw(1)) from dual
I've no idea whether MySQL will accept this but with some testing you should be able to work it out.
1. For clarity, I've never tried it in either direction.
Hah! I found a solution. Dropping it here in case it helps someone else. It's not pretty, but it works.
I used the old EXECUTE IMMEDIATE trick.
Basically, I created a variable sql_stmt varchar2(4000) and wrote code like:
sql_stmt := 'insert into "app_user"#mobileapi (USERNAME, VERSION, ACCOUNT_EXPIRED, ACCOUNT_LOCKED, CIPHER_PASSPHRASE, ENABLED, PASSWD, PASSWORD_EXPIRED)
values ('''||CU_rec.USERNAME||'','||CU_rec.VERSION||', '||CU_rec.ACCOUNT_EXPIRED||', '||CU_rec.ACCOUNT_LOCKED||', '''||CU_rec.CIPHER_PASSPHRASE||''', '||
CU_rec.ENABLED||', '''||CU_rec.PASSWD||''', '||CU_rec.PASSWORD_EXPIRED||')';
EXECUTE IMMEDIATE sql_stmt;
Something like that anyway (the quotes might not line up, as I hacked this a bit from the actual code). Looking at the contents of sql_stmt, I get:
insert into "app_user"#mobileapi (USERNAME, VERSION, ACCOUNT_EXPIRED, ACCOUNT_LOCKED, CIPHER_PASSPHRASE, ENABLED, PASSWD,PASSWORD_EXPIRED)
values ('user#email.com', 0, 0, 0, 'asdfastrwaebawavgansdhnsgjsjsh', 1, 'awercbcakwjerhcawuerawieubkahbewvkruh', 0)
The EXECUTE IMMEDIATE completes, and checking the target table, the values are there.
Possibly a crappy solution, but better than nothing.