Get the highest/lowest value from 2 columns - sql

I've got this table:
BP1 BP2
-----------------------------
140 80
153 88
90 162
98 214
98 69
I want to organize it into 2 columns: one of high BP and other of low BP:
Expected output:
BP_High BP_Low
---------------------------------
140 80
153 88
162 90
214 98
98 69
*all values are int
I've tried:
SELECT CASE WHEN BP1 > BP2 THEN BP1
WHEN BP1 < BP2 THEN BP2 END BP_High,
CASE WHEN BP1 > BP2 THEN BP2
WHEN BP1 < BP2 THEN BP1 END BP_Low
FROM Table
and it does not work...it gives me all mixed up:
BP_High BP_Low
---------------------------------
140 80
153 88
90 162
98 214
98 69
I've also tried:
SELECT CASE WHEN BP1 > BP2 THEN BP1
ELSE BP2 END BP_High,
CASE WHEN BP1 > BP2 THEN BP2
ELSE BP1 END BP_Low
FROM Table
Is there any other way then CASE WHEN to in order to get the highest/lowest value from 2 columns?

Your third attempt is almost correct, and you in fact can use CASE expressions here:
SELECT
CASE WHEN BP1 > BP2 THEN BP1 ELSE BP2 END AS BP_High,
CASE WHEN BP1 < BP2 THEN BP1 ELSE BP2 END AS BP_Low
FROM yourTable;
On other databases, such as MySQL, Postgres, or SQLite, there are LEAST() and GREATEST() scalar functions available. On those databases, your query can be simplified to:
SELECT
GREATEST(BP1, BP2) AS BP_High,
LEAST(BP1, BP2) AS BP_Low
FROM yourTable;

Related

I am trying to execute a SQL query, it's have some case syntax error

I am trying to execute this below query, but it is showing case syntax error
SELECT runtimeminutes,avgrating, sum(numvotes), count(*) as numberoccurences
CASE
WHEN runtimeminutes BETWEEN 0 and 60 then '0-60'
when runtimeminutes BETWEEN 61 and 120 then '61-120'
when runtimeminutes BETWEEN 121 and 180 then '121-180'
when runtimeminutes between 181 and 240 then '181-240'
when runtimeminutesBETWEEN 241 and 300 then '241-300'
else '301 and greater'
end as RunTimerange
FROM title_basics
Can anyone help me with this?

Is it possible to CAST as FLOAT from an IIF statement?

Is it possible to CAST as FLOAT from an IIF statement?
SELECT TOP 100 PeopleID, RateCount, IIF (People.RateCount < 100,
CAST(People.RateCount/100 as FLOAT), 1) as RateWeight
FROM People WHERE People.RateCount > 0 ORDER BY People.DateAdded DESC
The result I'm getting is
PeopleID RateCount RateWeight
8548 674 1
135698 30 0
426755 2 0
336714 106 1
276739 43 0
536577 7 0
57674 81 0
79670 32 0
44674 901 1
146784 16 0
What I want is
PeopleID RateCount RateWeight
8548 674 1
135698 30 .30
426755 2 .02
336714 106 1
276739 43 .43
536577 7 .07
57674 81 .81
79670 32 .32
44674 901 1
146784 16 .16
Is there a better way of doing this?
When performing division, the data types of the numbers being divided control the resulting data type. To get a FLOAT or DECIMAL result, one of the numbers must already be FLOAT or DECIMAL, i.e.:
SELECT TOP 100 PeopleID,
RateCount,
IIF (People.RateCount < 100, People.RateCount/CAST(100 as FLOAT), 1) as RateWeight
FROM People
WHERE People.RateCount > 0
ORDER BY People.DateAdded DESC
Alternately, get rid of the CAST and just make the value 100 into 100.0
SELECT TOP 100 PeopleID,
RateCount,
IIF (People.RateCount < 100, People.RateCount/100.0, 1) as RateWeight
FROM People
WHERE People.RateCount > 0
ORDER BY People.DateAdded DESC

Why can't I convert this varchar to numeric?

I have a table with values pasted in, but they initially start as varchar. I need to convert them to numeric, so I did
convert(decimal(10,3), cw.col7)
But this is returning Error 8114: Error converting data type varchar to numeric. The reason I made this question is because it does not give this error for a similar data set. Are there sometimes strange anomalies when using convert() or decimal()? Or should I maybe convert to float first?
The data:
col7
490.440
2
934
28,108.000
33,226.000
17,347.000
1,561.000
57
0
421.350
64
1,100.000
0
0
3,584
202.432
0
3,280
672.109
1,150
0
104
411.032
18,016
40
510,648
443,934.000
18,705
322,254
301
9,217
18,075
16,100
395
706,269
418,313
7,170
40,450
2,423
1,300
2,311
94,000.000
17,463
0
228
884
557
153
13
0
0
212.878
45,000.000
152
24,400
3,675
11,750
987
23,725
268,071
4,520.835
286,000
112,912.480
9,000
1,316
1,020
215,244
123,967
6,911
1,088.750
138,644
16,924
7,848
33,017
464,463
618
72,391
9,367
507,635.950
588,087
92,890
17,266
0
1,414,547
89,080
664
101,635
1,552,992
175
356
7,000
0
0
445
507,381
24,016
469,983
0
0
147,737
3,521
88,210
18,433.000
21,775
3,607
34,774
7,642
42,680
1,255
10,880
350,409.800
19,394.520
2,476,257.400
778.480
1,670.440
9,710
24,931.600
3,381.800
2,900
18,000
4,121
3,750
62,200
952
29.935
17.795
11.940
902
36,303
1,240
1,020
617
817
620
92,648
70,925
82,924
19,162.200
1,213.720
2,871
3,180
91,600
645
607
155,100
6
840
1,395
112
6,721
3,850
40
4,032
5,912
1,040
872
56
1,856
179
Try_Convert(money,...) will handle the comma, while decimal(10, 3) will return null
Example
Select col7
,AsMoney = Try_Convert(money,col7)
,AsDecimal = Try_Convert(decimal(10, 3),col7)
from YourTable
Returns
Try using cast and remove comma
SELECT CAST(repalce(cw.col7,',','') AS DECIMAL(10,3))
from your_table
and as suggested by Jhon Cappelleti you need more that 3 decimal so you should use
SELECT CAST(repalce(cw.col7,',','') AS DECIMAL(12,4))
from your_table
Run this query:
select cw.col7
from cw
where try_convert(decimal(10, 3), cw.col7) is null;
This will show you the values that do not convert successfully. (If cw.col7 could be NULL then add and cw.col7 is not null to make the output more meaningful.)

SQL WHERE clause not filtering out null column

I don't understand why I'm getting certain results when I run a SQL query. This is the query:
SELECT A.flag, B.type, B.aID
FROM A
LEFT JOIN B ON B.aID = A.aID
WHERE A.startDate = '2013-01-07'
AND (A.flag = 1 OR B.type IS NOT NULL)
aID is the primary key on table A.
This is the result I get:
flag type aID
---- ---- ----
0 NULL NULL
I would have expected there to be no results. I am confused because A.flag is not 1 and B.type is null, which seems contrary to my WHERE clause. Note that there was no match for this row on table B, since B.aID is null in the result. When I run the query with only one of A.flag = 1 and B.type IS NOT NULL instead of both, no results are returned instead of one result.
Curiously, when I replace B.type in the SELECT statement with ISNULL(B.type, 'X'), no results are returned. The same happens when I add AND B.type IS NOT NULL to the LEFT JOIN.
Why am I getting this result?
Edit: Sample data
Here is a query that gets rows from table A using two different start dates:
SELECT * FROM A
WHERE A.startDate IN ('2013-01-07', '2012-11-23')
I get the following results (leaving out 6 columns for clarity):
aID cID sID psID startDate flag
------- ---- ---- ---- ----------------------- -----
23844 75 72 86 2013-01-07 00:00:00 0
23940 75 72 86 2012-11-23 00:00:00 1
21061 76 73 87 2012-11-23 00:00:00 0
21293 76 74 88 2012-11-23 00:00:00 0
21477 77 75 89 2012-11-23 00:00:00 0
21711 78 76 90 2012-11-23 00:00:00 0
21944 79 77 91 2012-11-23 00:00:00 0
22176 80 78 92 2012-11-23 00:00:00 0
22410 81 79 93 2012-11-23 00:00:00 0
22643 82 80 94 2012-11-23 00:00:00 0
23344 83 81 95 2012-11-23 00:00:00 0
22876 84 82 96 2012-11-23 00:00:00 0
23639 85 83 97 2012-11-23 00:00:00 0
23109 89 84 98 2012-11-23 00:00:00 0
(14 row(s) affected)
Using the aID that we found for 2013-01-07, we can see from this next query that there is no entry in table B that corresponds to that start date.
SELECT * FROM B
WHERE B.aID = 23844
This returns no results.
Using the aID's that we found for 2012-11-23, we can see that all but one of these have a corresponding entry in table B.
SELECT * FROM B
WHERE B.aID IN (23940,
21061,
21293,
21477,
21711,
21944,
22176,
22410,
22643,
23344,
22876,
23639,
23109)
Results:
bID aID type duration iMinutes
----- ------ ----- -------- ---------
5836 21061 M 0 0
5893 21293 M 0 0
5916 21477 M 0 0
5975 21711 M 0 0
6033 21944 M 0 0
6092 22176 M 0 0
6150 22410 M 0 0
6208 22643 M 0 0
6266 22876 M 0 0
6530 23109 M 0 0
6382 23344 M 0 0
6478 23639 M 0 0
(12 row(s) affected)
Turns out this is happening because there are no service packs installed on this database (2008). Other databases with SP1 installed do not have this issue.
It's because you are doing a LEFT (OUTER) JOIN. Perhaps an INNER JOIN is what you had in mind?

Calculating difference from previous record

May I ask for your help with the following please ?
I am trying to calculate a change from one record to the next in my results. It will probably help if I show you my current query and results ...
SELECT A.AuditDate, COUNT(A.NickName) as [TAccounts],
SUM(IIF((A.CurrGBP > 100 OR A.CurrUSD > 100), 1, 0)) as [Funded]
FROM Audits A
GROUP BY A.AuditDate;
The query gives me these results ...
AuditDate D/M/Y TAccounts Funded
--------------------------------------------
30/12/2011 506 285
04/01/2012 514 287
05/01/2012 514 288
06/01/2012 516 288
09/01/2012 520 289
10/01/2012 522 289
11/01/2012 523 290
12/01/2012 524 290
13/01/2012 526 291
17/01/2012 531 292
18/01/2012 532 292
19/01/2012 533 293
20/01/2012 537 295
Ideally, the results I would like to get, would be similar to the following ...
AuditDate D/M/Y TAccounts TChange Funded FChange
------------------------------------------------------------------------
30/12/2011 506 0 285 0
04/01/2012 514 8 287 2
05/01/2012 514 0 288 1
06/01/2012 516 2 288 0
09/01/2012 520 4 289 1
10/01/2012 522 2 289 0
11/01/2012 523 1 290 1
12/01/2012 524 1 290 0
13/01/2012 526 2 291 1
17/01/2012 531 5 292 1
18/01/2012 532 1 292 0
19/01/2012 533 1 293 1
20/01/2012 537 4 295 2
Looking at the row for '17/01/2012', 'TChange' has a value of 5 as the 'TAccounts' has increased from previous 526 to 531. And the 'FChange' would be based on the 'Funded' field. I guess something to be aware of is the fact that the previous row to this example, is dated '13/01/2012'. What I mean is, there are some days where I have no data (for example over weekends).
I think I need to use a SubQuery but I am really struggling to figure out where to start. Could you show me how to get the results I need please ?
I am using MS Access 2010
Many thanks for your time.
Johnny.
Here is one approach you could try...
SELECT B.AuditDate,B.TAccounts,
B.TAccount -
(SELECT Count(NickName) FROM Audits WHERE AuditDate=B.PrevAuditDate) as TChange,
B.Funded -
(SELECT Count(*) FROM Audits WHERE AuditDate=B.PrevAuditDate AND (CurrGBP > 100 OR CurrUSD > 100)) as FChange
FROM (
SELECT A.AuditDate,
(SELECT Count(NickName) FROM Audits WHERE AuditDate=A.AuditDate) as TAccounts,
(SELECT Count(*) FROM Audits WHERE (CurrGBP > 100 OR CurrUSD > 100)) as Funded,
(SELECT Max(AuditDate) FROM Audits WHERE AuditDate<A.AuditDate) as PrevAuditDate
FROM
(SELECT DISTINCT AuditDate FROM Audits) AS A) AS B
Instead of using a Group By I've used subquerys to get both TAccounts and Funded, as well as the Previous Audit Date, which is then used on the main SELECT statement to get TAccounts and Funded again but this time for the previous date, so that any required calculation can be done against them.
But I would imagine this may be slow to process
It's a shame MS never made this type of thing simple in Access, how many rows are you working with on your report?
If it's under 65K then I would suggest dumping the data on to an Excel spreadsheet and using a simple formula to calculate the different between rows.
You can try something like the following (sql is untested and will require some changes)
SELECT
A.AuditDate,
A.TAccounts,
A.TAccounts - B.TAccounts AS TChange,
A.Funded,
A.Funded - B.Funded AS FChange
FROM
( SELECT
ROW_NUMBER() OVER (ORDER BY AuditDate DESC) AS ROW,
AuditDate,
COUNT(NickName) as [TAccounts],
SUM(IIF((CurrGBP > 100 OR CurrUSD > 100), 1, 0)) as [Funded]
FROM Audits
GROUP BY AuditDate
) A
INNER JOIN
( SELECT
ROW_NUMBER() OVER (ORDER BY AuditDate DESC) AS ROW,
AuditDate,
COUNT(NickName) as [TAccounts],
SUM(IIF((CurrGBP > 100 OR CurrUSD > 100), 1, 0)) as [Funded]
FROM Audits
GROUP BY AuditDate
) B ON B.ROW = A.ROW + 1