I have a table with a column which contains odd and even numbers (ex. 1, 2, 3, 4, 5 etc).
I have to create an output table or view with two columns, odd_numbers and even_numbers, like this:
odd_numbers even_numbers
1 2
3 4
5 6
How do I do that? The condition is easy (where mod (num,2) = 0 or <> 0) but how do I populate the view?
I can't figure it out.
One method uses conditional aggregation:
select min(num), max(num)
from t
group by floor( (num - 1) / 2)
Note that this doesn't use mod(). It basically divides the number by 2 to identify the row (the - 1 is just so the min is odd and the max even).
EDIT:
MS Access (and some other databases) does integer division, so you can just use group by (num - 1) / 2.
If some number can be missing, then:
select max(iif(mod(num, 2) = 1, num, null),
max(iif(mod(num, 2) = 0, num, null)
from t
group by floor( (num - 1) / 2)
This runs in Access (and most other dbs):
SELECT
Value AS Odd,
Value + 1 AS Even
FROM
Table1
WHERE
Value Mod 2 <> 0
Related
Let's say I have a very basic table:
DAY_ID
Value
Inserts
5
8
2
4
3
0
3
3
0
2
4
1
1
8
0
I want to be able to "loop" through the Inserts column, and add that many # of rows.
For each added row, I want DAY_ID to be decreased by 1 and Value to remain the same, Inserts column is irrelevant we can set to 0.
So 2 new rows should be added from DAY_ID = 5 and Value = 8, and 1 new row with DAY_ID = 2 and Value = 4. The final output of the new rows would be:
DAY_ID
Value
Inserts
(5-1)
8
0
(5-2)
8
0
(2-1)
4
0
I haven't tried much in SQL Server, I was able to create a solution in R and Python using arrays, but I'm really hoping I can make something work in SQL Server for this project.
I think this can be done using a loop in SQL.
Looping is generally not the way you solve any problems in SQL - SQL is designed and optimized to work with sets, not one row at a time.
Consider this source table:
CREATE TABLE dbo.src(DAY_ID int, Value int, Inserts int);
INSERT dbo.src VALUES
(5, 8, 2),
(4, 3, 0),
(3, 3, 0),
(2, 4, 1),
(1, 8, 0);
There are many ways to "explode" a set based on a single value. One is to split a set of commas (replicated to the length of the value, less 1).
-- INSERT dbo.src(DAY_ID, Value, Inserts)
SELECT
DAY_ID = DAY_ID - ROW_NUMBER() OVER (PARTITION BY DAY_ID ORDER BY ##SPID),
src.Value,
Inserts = 0
FROM dbo.src
CROSS APPLY STRING_SPLIT(REPLICATE(',', src.Inserts-1), ',') AS v
WHERE src.Inserts > 0;
Output:
DAY_ID
Value
Inserts
1
4
0
4
8
0
3
8
0
Working example in this fiddle.
In SQL there are aggregation operators, like AVG, SUM, COUNT. Why doesn't it have an operator for multiplication? "MUL" or something.
I was wondering, does it exist for Oracle, MSSQL, MySQL ? If not is there a workaround that would give this behaviour?
By MUL do you mean progressive multiplication of values?
Even with 100 rows of some small size (say 10s), your MUL(column) is going to overflow any data type! With such a high probability of mis/ab-use, and very limited scope for use, it does not need to be a SQL Standard. As others have shown there are mathematical ways of working it out, just as there are many many ways to do tricky calculations in SQL just using standard (and common-use) methods.
Sample data:
Column
1
2
4
8
COUNT : 4 items (1 for each non-null)
SUM : 1 + 2 + 4 + 8 = 15
AVG : 3.75 (SUM/COUNT)
MUL : 1 x 2 x 4 x 8 ? ( =64 )
For completeness, the Oracle, MSSQL, MySQL core implementations *
Oracle : EXP(SUM(LN(column))) or POWER(N,SUM(LOG(column, N)))
MSSQL : EXP(SUM(LOG(column))) or POWER(N,SUM(LOG(column)/LOG(N)))
MySQL : EXP(SUM(LOG(column))) or POW(N,SUM(LOG(N,column)))
Care when using EXP/LOG in SQL Server, watch the return type http://msdn.microsoft.com/en-us/library/ms187592.aspx
The POWER form allows for larger numbers (using bases larger than Euler's number), and in cases where the result grows too large to turn it back using POWER, you can return just the logarithmic value and calculate the actual number outside of the SQL query
* LOG(0) and LOG(-ve) are undefined. The below shows only how to handle this in SQL Server. Equivalents can be found for the other SQL flavours, using the same concept
create table MUL(data int)
insert MUL select 1 yourColumn union all
select 2 union all
select 4 union all
select 8 union all
select -2 union all
select 0
select CASE WHEN MIN(abs(data)) = 0 then 0 ELSE
EXP(SUM(Log(abs(nullif(data,0))))) -- the base mathematics
* round(0.5-count(nullif(sign(sign(data)+0.5),1))%2,0) -- pairs up negatives
END
from MUL
Ingredients:
taking the abs() of data, if the min is 0, multiplying by whatever else is futile, the result is 0
When data is 0, NULLIF converts it to null. The abs(), log() both return null, causing it to be precluded from sum()
If data is not 0, abs allows us to multiple a negative number using the LOG method - we will keep track of the negativity elsewhere
Working out the final sign
sign(data) returns 1 for >0, 0 for 0 and -1 for <0.
We add another 0.5 and take the sign() again, so we have now classified 0 and 1 both as 1, and only -1 as -1.
again use NULLIF to remove from COUNT() the 1's, since we only need to count up the negatives.
% 2 against the count() of negative numbers returns either
--> 1 if there is an odd number of negative numbers
--> 0 if there is an even number of negative numbers
more mathematical tricks: we take 1 or 0 off 0.5, so that the above becomes
--> (0.5-1=-0.5=>round to -1) if there is an odd number of negative numbers
--> (0.5-0= 0.5=>round to 1) if there is an even number of negative numbers
we multiple this final 1/-1 against the SUM-PRODUCT value for the real result
No, but you can use Mathematics :)
if yourColumn is always bigger than zero:
select EXP(SUM(LOG(yourColumn))) As ColumnProduct from yourTable
I see an Oracle answer is still missing, so here it is:
SQL> with yourTable as
2 ( select 1 yourColumn from dual union all
3 select 2 from dual union all
4 select 4 from dual union all
5 select 8 from dual
6 )
7 select EXP(SUM(LN(yourColumn))) As ColumnProduct from yourTable
8 /
COLUMNPRODUCT
-------------
64
1 row selected.
Regards,
Rob.
With PostgreSQL, you can create your own aggregate functions, see http://www.postgresql.org/docs/8.2/interactive/sql-createaggregate.html
To create an aggregate function on MySQL, you'll need to build an .so (linux) or .dll (windows) file. An example is shown here: http://www.codeproject.com/KB/database/mygroupconcat.aspx
I'm not sure about mssql and oracle, but i bet they have options to create custom aggregates as well.
You'll break any datatype fairly quickly as numbers mount up.
Using LOG/EXP is tricky because of numbers <= 0 that will fail when using LOG. I wrote a solution in this question that deals with this
Using CTE in MS SQL:
CREATE TABLE Foo(Id int, Val int)
INSERT INTO Foo VALUES(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)
;WITH cte AS
(
SELECT Id, Val AS Multiply, row_number() over (order by Id) as rn
FROM Foo
WHERE Id=1
UNION ALL
SELECT ff.Id, cte.multiply*ff.Val as multiply, ff.rn FROM
(SELECT f.Id, f.Val, (row_number() over (order by f.Id)) as rn
FROM Foo f) ff
INNER JOIN cte
ON ff.rn -1= cte.rn
)
SELECT * FROM cte
Not sure about Oracle or sql-server, but in MySQL you can just use * like you normally would.
mysql> select count(id), count(id)*10 from tablename;
+-----------+--------------+
| count(id) | count(id)*10 |
+-----------+--------------+
| 961 | 9610 |
+-----------+--------------+
1 row in set (0.00 sec)
I came across the following SQL statement:
SELECT A.NAME
FROM THE_TABLE A
WHERE A.NAME LIKE '%JOHN%DOE%'
AND ((A.NUM_FIELD/1) - (A.NUM_FIELD/2)*2 <> 0)
That last condition, "((A.NUM_FIELD/1) - (A.NUM_FIELD/2)*2 <> 0)" is what baffles me. Depening on the implementation of order of operations, it should always result to 0 or A.NUM_FIELD / 2.
How does SQL still return records from this view? If it always results to half the original value, why have it? (This is a delivered SQL package)
Probably integer division, so an odd NUM_FIELD is going to be one less.
MSDN says:
If an integer dividend is divided by an integer divisor, the result is
an integer that has any fractional part of the result truncated.
if the NUM_FIELD is an integer, and an odd one- then
(A.NUM_FIELD/1) - (A.NUM_FIELD/2)*2
is equal to one
What SQL implementation is this?
As noted,
(x/1) - (x/2)*2
is equivalent to
X - (2*(x/2))
which, if integer division is being performed yields 0 or 1 depending on whether the value is even or odd:
x x/2 2*(x/2) x-(2*(x/2))
- --- ------- -----------
0 0 0 0
1 0 0 1
2 1 2 0
3 1 2 1
4 2 4 0
...
if so, it seems like an odd way way of checking for odd/even values, especially since most SQL implementations that I'm aware of support a modulo operator or function, either x % y or mod(x,y).
The seemingly extraneous division by 1 makes me think the column in question might be floating point. Perhaps the person who coded the query is trying to check for jitter or fuzzyness in the low order bits of the floating point column?
if you modified the query to return all the intermediate values of the computation:
SELECT A.NAME as Name ,
A.NUM_FIELD as X ,
A.NUM_FIELD / 1 as X_over_1 ,
A.NUM_FIELD / 2 as X_over_2 ,
( X.NUM_FIELD / 2 )
* 2 as 2x_over_2 ,
( A.NUM_FIELD / 1 )
- ( A.NUM_FIELD / 2 ) * 2 as Delta ,
case when ( ( A.NUM_FIELD / 1 ) - ( A.NUM_FIELD / 2 ) * 2 ) <> 0
then 'return'
else 'discard'
end as Row_Status
FROM THE_TABLE A
WHERE A.NAME LIKE '%JOHN%DOE%'
and then executed it, what results do you get?
How can I select every thrid row from the table?
if a table has
1
2
3
4
5
6
7
8
9
records
it should pick up 3, 6,9 record. regards less what their data is.
Modulo is what you want...
Assuming contiguous values:
SELECT *
FROM Mytable
WHERE [TheColumn] Mod 3 = 0
And with gaps
SELECT *
FROM Mytable
WHERE DCount("TheColumn", "table", "TheColumn <= " & [TheColumn]) Mod 3 = 0
Edit: To exclude every 3rd record, ...Mod 3 <> 0
If its SQL you could use the row_number and over commands. see this, then where rownumvar % 3 =0 but not sure if that works in access.
Or you could put the table into a recordset and iterate through checking the index for % 3=0 if your using any kind of code.
How about a Count() on a field that has unique members. (id?) then % 3 on that.
Having this table, I would like to find the rows with Val fitting my Indata.
Tol field is a tolerance (varchar), that can be either an integer/float or a percentage value.
Row Val Tol Outdata
1 24 0 A
2 24 5 B
3 24 10 C
4 32 %10 D
5 32 1 E
Indata 30 for example should match rows 3 (24+10=34) and 4 (32-10%=28.8).
Can this be done in mySQL? CREATE FUNCTION?
This is going to be rather difficult to do in MySQL with that table and column design. How do you plan to differentiate what sort of comparison should be done? By doing a string comparison to see if your varchar field contains a percentage sign?
I would suggest breaking your tolerance field into (at least) two int/float columns, say tol and tol_pct. For flexibility, I would represent tol_pct as a decimal (10% => .10). Then, you can do a query that looks like:
select *
from table
where
(Indata between Val - tol and Val + tol)
or (Indata between Val * (1 + tol_pct) and Val * (1 - tol_pct))
I don't have a MySQL install to test it on, but this example is converted from Oracle sql syntax. You have to use string functions to determine if the tol is a percent and act accordingly to calculate the min and max range for that field. Then you can use a between clause.
select *
from (select t.*,
case when substr(tol, 1, 1) = '%' then
t.val * (1 + convert('.' + substr(tol, 2), number))
else
t.val + convert(tol, number)
end maxval,
case when substr(tol, 1, 1) = '%' then
t.val * (1 - convert('.' + substr(tol, 2), number))
else convert(t.val - tol, number)
end minval
from mytable
) t
where 30 between minval and maxval
;
Sure it can be done. But let me tell you that you better review your database design as it conflicts with normalization quite a bit. See http://en.wikipedia.org/wiki/Database_normalization for a quick overview.