SQl Use IIF to compare 2 values in same row - sql

I am using SQL in MS Access and need to compare 2 values in a row to determine the result of a 3rd field.
The "Yearmove" field does not have a value in all cases. Here is the test code I am running
SELECT z.SCHOOL, z.Year as Year, ProgBuild.BldgNo, ProgMoveBuild.yearmove AS Yearmove,
IIF([Year]=[Yearmove], 1, 0) AS Result
The results are fine in the cases where "Yearmove" is blank, and show 0 as expected. Anyplace "Yearmove" has a number the Result field reads "#ERROR", so both when the condition is met and when it is not. I have tried populating the "YEAR" field with both text (e.g. "2014") and non-text (e.g. 2014) but get the same result. All data is numeric.
Here is what a section of the results look like:
SCHOOL Year BldgNo Yearmove Result
254 2014 254 0
256 2014 256 0
260 2014 260 0
261 2014 261 0
262 2014 202 0
301 2014 301 0
307 2014 307 2019 #ERROR
313 2014 313 2019 #ERROR
314 2014 314 0
321 2014 321 0
322 2014 322 0

This query throws an error, "Data type mismatch in criteria expression":
SELECT IIf('2014'=2014, 1, 0)
So I suspect your Year and yearmove fields are different datatypes: one is numeric; and the other is text.
Find out what datatypes you're dealing with ...
SELECT
z.Year,
TypeName(z.Year) AS TypeOfYear,
ProgMoveBuild.yearmove,
TypeName(ProgMoveBuild.yearmove) AS TypeOfyearmove
FROM [whatever you have now as your data source(s)]
If changing the datatype of one of those fields not practical, you can cast a field's values to another type for the IIf condition in your query. CStr() will cast a numeric value to a string. And Val() will cast a string value to a number. However, either of those functions will complain when you give them Nulls. So you can use Nz() to substitute something else for Null before you feed the value to CStr() or Val().

Related

Regex in SQL Server, how can i found only certain length of integers

I have a table in SQL Server and a column ( consider the column is of varchar or INT data type), The column has values and most of them are integers.
How can I query only integers with length 3, not more than 3 or less than 3 using Regular Expression?
is it possible in SQL Server?
do I need to install any additional libraries?
Input
column
123
234
4532
223
2e34
234
22
23344
Expected Output:
Column
123
234
223
234
SQL Server does not have Regex. Even if it did, I wouldn't recommend it here
You can just use a cast and BETWEEN
WHERE TRY_CAST(YourColumn AS int) BETWEEN 100 AND 999
If the column is actually an int then you don't even need a cast.

How to group years in decades in sqlite3 in jupyter notebook?

I'm suppose to Find the decade D with the largest number of films and the total number of films in D. A decade is a sequence of 10 consecutive years. For example, say in your database you have movie information starting from 1965. Then the first decade is 1965, 1966, ..., 1974; the second one is 1967, 1968, ..., 1976 and so on.
I'm suppose to implement this in jupyter note book where I imorpted sqlite3
I wrote the following code for it.
Select count(*) as total_films,concat(decade,'-',decade+9)
FROM (Select floor(YEAR('year')/10)*10 as decade FROM movie) t
GROUP BY decade
Order BY total_films desc;
However, the notebook threw error like "no such function: floor" and "no such function: Year" and no such function: concat"
Therefore, after going through sqlite documentation I changed code to
Select count(*) as total_films,decade||'-'||decade+9
FROM (Select cast(strftime('%Y',year)/10 as int)*10 as decade FROM movie) t
GROUP BY decade
Order BY total_films desc;
However, I got an incorrect output :
count(*) decade||'-'||decade+9
0 117 NaN
1 3358 -461.0
Would appreciate insights on why this is happening.
Updating question after going through comments by c.Perkins
1) I began, checking the type of year column
using the query PRAGMA table_info(movie)
Got the following result
cid name type notnull dflt_value pk
0 0 index INTEGER 0 None 0
1 1 MID TEXT 0 None 0
2 2 title TEXT 0 None 0
3 3 year TEXT 0 None 0
4 4 rating REAL 0 None 0
5 5 num_votes INTEGER 0 None 0
Since the year column is of the type text I changed to int using the cast function and check for nulls or NaN SELECT CAST(year as int) as yr FROM MOVIE WHERE yr is null
I didn't get any results, therefore it appears there are no nulls. However, on using the query SELECT CAST(year as int) as yr FROM MOVIE order by yr asc I see a lot of zeros in the year column
yr
0 0
1 0
2 0
3 0
4 0
-
-
-
-
3445 2018
3446 2018
3447 2018
3448 2018
3449 2018
3450 2018
From the above we see that the year is given as it is and in another stamp, therefore using strftime('%Y', year) did not yield result as mentioned in the comment.
Therefore, keeping all the above in mind, I changed the inner query to
SELECT (CAST( (year/10) as int) *10) as decade FROM MOVIE WHERE decade!=0 order by decade asc
Output for the above query :
decade
0 1930
1 1930
2 1930
3 1930
4 1930
5 1930
6 1940
7 1940
8 1940
-
-
-
3353 2010
3354 2010
3355 2010
3356 2010
3357 2010
Finally, placing this inner query, in the first query I wrote above
Select count(*) as total_films,decade||'-'||decade+9 as period
FROM (SELECT (CAST( (year/10) as int) *10) as decade FROM MOVIE WHERE decade!=0 order by decade asc)
GROUP BY decade
Output :
total_films period
0 6 1939
1 12 1949
2 71 1959
3 145 1969
4 254 1979
5 342 1989
6 551 1999
7 959 2009
8 1018 2019
As far as I can see the only issue is with period column where instead of showing 1930-1939 it is only showing 1939 and so on, if is using || is not right, is there anythother function that could be used ? because concat is not working.
Thanks in advance.
Pending updates to the question as requested in comments, here are a few immediate points that might help solve the problem without having all details:
Does the movie.year column contain null values? Likewise non-numeric or non-date values? the NaN (Not A Number) result likely indicates a null/invalid data in the source. (Technically there is no such NaN value in SQLite, so I'm assuming that the question data is copied form some other data grid or processed output.)
What type of data is in the column movie.year? Does it contain full ISO-8601 date strings or a Julian-date numeric value? Or does it only contain the year (as the column name implies)? If it only contains the year (as a string or integer), then the function call like strftime('%Y', year) will NOT return what you expect and is unnecessary. Just refer to the column directly.
I suspect this is where the -461.0 is coming from.
The operator / is an "integer division" operator if both operands are integers. A valid isolated year value will be an integer and the literal 10 is of course an integer, so integer division will automatically drop any decimal part and returns only the integer part of the division without having to explicitly cast to integer.
According to sqlite docs, the concatenation operator || has highest precedence. That means in the expression decade||'-'||decade+9, the concatenation is applied first so that one possible intermediate would be '1930-1930'+9. (Technically I would consider this result undefined since the string value does not contain a basic data type. In practices on my system, the string is apparently interpreted as 1930 and the overall result is the integer value 1939. Either way you will get unexpected bogus results rather than the desired string.)

How to sum multiple rows based on the id filter criteria?

I have table with record_id and record_value. Query should return all id's and values but at the same time I need to return sum for specific group of id's. Here is example of my data:
record_id record_value
54 3
56 0
78 11
98 7
103 1
78 0
44 0
67 1
68 3
69 1
Query that I have returns rows with id's and values. I would like to get some of these columns as well in query result. Here is what I tried:
SELECT
record_id,
record_value
CASE
WHEN record_id IN ('54','56','67','68','69') THEN SUM(record_value)
ELSE ''
END AS RowSum
FROM Records
RowSum should return 19 but instead I'm getting an error:
SQL Error [257] [37000]: Implicit conversion from datatype 'VARCHAR' to 'NUMERIC' is not allowed. Use the CONVERT function to run this query.
I use Sybase database with DBeaver.
You can't use multiple results in one query. You can try with an UNION ALL
If you use CASE then both WHERE clauses should have the same type. You have used a NUMERIC (for SUM) an VARCHAR (for empty string ''). You need to unify them.
The code you might use is:
SELECT
record_id,
record_value,
FROM Records
union all
select null,
CASE
WHEN record_id IN ('54','56','67','68','69') THEN convert(varchar, SUM(record_value))
ELSE ''
END AS RowSum

Get rid of #Error in Access 2007 group footer report

I am creating a report in Access 2007 and I want to do the average, maximum, and minimum of several lab results. When I enter the following in the control source box, I get an #Error message in the group footer when all records being subtotaled are null when displaying the report. How can I get rid of this #Error and have the results return no value at all.
=CDbl(Avg([Arsenic]))
Thus data might look like this in my report
Serum
_______________________
Arsenic Iron
30 10
30
15
____________________
Avg 25 10
Max 30 10
Min 15 10
__________________________
Liver
__________________________
Arsenic Iron
8
0
2
____________________
Avg #Error 5
Max #Error 8
Min #Error 0
Many thanks
If you use just =Avg([Arsenic]), it'll be blank. Whats causing the #Error is when Avg() returns a blank, CDbl has a null input. If you absolutely must have CDbl() for whatever reason, then
=IIf(Avg([Arsenic]) Is Null,"",CDbl(Avg([Arsenic])))
will work

SQL MAX() Function

I found a very interesting/strange thing about MAX() function in SQL.
I have column ID with varchar2(20) data type, having following entries:-
ID
1
2
3
4
5
6
9
99
909
As per my understanding if i use "select max(ID) from table;" I should get 909 as the result but i get 99. Can somebody explain why this is happening?
You have misunderstood - since the column is a varchar, not numeric, it is sorted by string values; 909 comes before 99, so 99 is the maximum.
To see the maximum numeric value of your column, try:
select max(to_number(ID)) from my_table
Since the column you are using MAX on is of type VARCHAR, it is going to sort the values based on a character-by-character evaluation. It selects 99 because 9 > 0, and it will ignore the rest of the string.
Your column is being represented as characters, not numbers. So think of it as ordering these alphabetically. Alphabetically 909 will come before 99 in ascending order.