Find the largest value from column using SQL? - sql

I am using SQL where I have column having values like
A B
X1 2 4 6 8 10
X2 2 33 44 56 78 98 675 891 11111
X3 2 4 672 234 2343 56331
X4 51 123 232 12 12333
I want a query to get the value from col B with col A which has max count of values. I.e output should be
x2 2 33 44 56 78 98 675 891 11111
Query I use:
select max(B) from table
Results in
51 123 232 12 12333

Assuming that both columns are strings, and that column B uses single space for separators and no leading/trailing spaces, you can use this approach:
SELECT A, B
FROM MyTable
ORDER BY DESC LENGTH(B)-LENGTH(REPLACE(B, ' ', ''))
FETCH FIRST 1 ROW ONLY
The heart of this solution is LENGTH(B)-LENGTH(REPLACE(B, ' ', '')) expression, which counts the number of spaces in the string B.
Note: FETCH FIRST N ROWS ONLY is Oracle-12c syntax. For earlier versions use ROWNUM approach described in this answer.

In case there is more than one separating space or more then one row meets criteria do this: count number of spaces (or groups of spaces) in each row using regexp_count(). Use rank to find most (groups of) spaces. Take only rows ranked as 1:
demo
select *
from (select t.*, rank() over (order by regexp_count(b, ' +') desc) rnk from t)
where rnk = 1

Related

How to: For each unique id, for each unique version, grab the best score and organize it into a table

Just wanted to preface this by saying while I do have a basic understanding, I am still fairly new to using Bigquery tables and sql statements in general.
I am trying to make a new view out of a query that grabs all of the best test scores for each version by each employee:
select emp_id,version,max(score) as score from `project.dataset.table` where type = 'assessment_test' group by version,emp_id order by emp_id
I'd like to take the results of that query, and make a new table comprised of employee id's with a column for each versions best score for that rows emp_id. I know that I can manually make a table for each version by including a "where version = a", "where version = b", etc.... and then joining all of the tables at the end but that doesn't seem like the most elegant solution plus there is about 20 different versions in total.
Is there a way to programmatically create a column for each unique version or at the very least use my initial query as maybe a subquery and just reference it, something like this:
with a as (
select id,version,max(score) as score
from `project.dataset.table`
where type = 'assessment_test' and version is not null and score is not null and id is not null
group by version,id
order by id),
version_a as (select score from a where version = 'version_a')
version_b as (select score from a where version = 'version_b')
version_c as (select score from a where version = 'version_c')
select
a.id as id,
version_a.score as version_a,
version_b.score as version_b,
version_c.score as version_c
from
a,
version_a,
version_b,
version_c
Example Picture: left table is example data, right table is expected output
Example Data:
id
version
score
1
a
88
1
b
93
1
c
92
2
a
89
2
b
99
2
c
78
3
a
95
3
b
83
3
c
89
4
a
90
4
b
90
4
c
86
5
a
82
5
b
78
5
c
98
1
a
79
1
b
97
1
c
77
2
a
100
2
b
96
2
c
85
3
a
83
3
b
87
3
c
96
4
a
84
4
b
80
4
c
77
5
a
95
5
b
77
Expected Output:
id
a score
b score
c score
1
88
97
92
2
100
99
85
3
95
87
96
4
90
90
86
5
95
78
98
Thanks in advance and feel free to ask any clarifying questions
Use below approach
select * from your_table
pivot (max(score) score for version in ('a', 'b', 'c'))
if applied to sample data in your question - output is
In case if versions is not known in advance - use below
execute immediate (select '''
select * from your_table
pivot (max(score) score for version in (''' || string_agg(distinct "'" || version || "'") || "))"
from your_table
)

Table returning cumulative sum

I have this table. It contains a column with points (a), a column with a playerid (b) and column with games(c). I would like to translate this table using SQL to a format in which values in column a get summed up. This would need to result in the table below. Column d contains the values summed by the previous value, column e contains the playerId en column f the gamenumber
So I would like this:
a b c
1 385 11255 1
2 378 11178 1
3 370 11551 1
4 264 11255 2
5 100 11178 2
6 405 11551 2
7 200 11255 3
8 412 11178 3
9 50 11551 3
Into this:
d e f
385 11255 1
649 11255 2
849 11255 3
378 11178 1
478 11178 2
890 11178 3
370 11551 1
775 11551 2
825 11551 3
You can use the SUM() OVER() window function (if your version of SQL Server supports it)
select b,c,sum(a) over(partition by b order by c) as running_sum
from tbl
On versions that don't support it, you can do this with cross apply.
select t.b,t.c,t1.total
from tbl t
cross apply (select sum(a) as total from tbl t1 where t1.b=t.b and t1.c<=t.c) t1
I think you want something like this:
select sum(a) over (partition by b order by c) as d, b as e, c as f
from t
order by e, f;
Cumulative sums with this syntax are supported since SQL Server 2012.

why Order by does not sort?

I have a query below, I want it to sort the data by id, but it doesn't sort at all.
Select distinct ec.category,ec.id
from print ec
order by ec.id asc
What could be the reason?
this is the output :
Looking at your data, the column data type is a varchar, aka 'text'.
If it is text, it sorts like text, according to the place the character occurs in the character set used.
So each column is ordered on the first character, then the second, etc. So 2 comes after 11.
Either make the column a numeric data type, like number, or use to_number in the sorting:
select distinct ec.category,ec.id
from print ec
order by to_number(ec.id)
The difference lies in the way varchar and number are sorted. in your case, since you have used varchar data type to store number, the sorting is done for the ASCII values.
NUMBERS when sorted as STRING
SQL> WITH DATA AS(
2 SELECT LEVEL rn FROM dual CONNECT BY LEVEL < = 11
3 )
4 SELECT rn, ascii(rn) FROM DATA
5 order by ascii(rn)
6 /
RN ASCII(RN)
---------- ----------
1 49
11 49
10 49
2 50
3 51
4 52
5 53
6 54
7 55
8 56
9 57
11 rows selected.
SQL>
As you can see, the sorting is based on the ASCII values.
NUMBER when sorted as a NUMBER itself
SQL> WITH DATA AS(
2 SELECT LEVEL rn FROM dual CONNECT BY LEVEL < = 11
3 )
4 SELECT rn, ascii(rn) FROM DATA
5 ORDER BY rn
6 /
RN ASCII(RN)
---------- ----------
1 49
2 50
3 51
4 52
5 53
6 54
7 55
8 56
9 57
10 49
11 49
11 rows selected.
SQL>
How to fix the issue?
Change the data type to NUMBER. As a workaround, you could use to_number.
Using to_number -
SQL> WITH DATA AS(
2 SELECT to_char(LEVEL) rn FROM dual CONNECT BY LEVEL < = 11
3 )
4 SELECT rn, ascii(rn) FROM DATA
5 ORDER BY to_number(rn)
6 /
RN ASCII(RN)
--- ----------
1 49
2 50
3 51
4 52
5 53
6 54
7 55
8 56
9 57
10 49
11 49
11 rows selected.
SQL>
Make sure the type of your "id" column is int. (integer = number)
Right now it is probably text, char or varchar(for text, strings).
You can't sort numbers alphabetically or strings/text chronologically like you are trying now.
when you sort a string datatype that has in values it produce result as
1
10
11
2
21 etc...
Hence
Change your Id datatype to int/bigint
You can only just cast/convert the datatype in a query
Select distinct ec.category,ec.id
from print ec
order by cast(ec.id as int) asc

Merge two row into two column with third column same as it is

I have SQL output like this :
LINE SIZE TOT_COUNT
A 20 113
A 40 3
B 20 4
B 40 2
C 20 142
C 40 452
But I want like this:
LINE 20 40
A 113 3
B 4 2
C 142 452
Note: This is already a output, not any column of any table.
select
line,
sum(case size when 20 then tot_count end) as "20", -- use min is the same.
sum(case size when 40 then tot_count end) as "40"
from
your_table
group by
line
If the first output is from another query, you can replace your_table with your query as an sub query.

sum of differencies of rows

I have example values in column like this:
values
-------
89
65
56
78
74
73
45
23
5
654
643
543
345
255
233
109
43
23
2
The values are rising up and then fall down to 0 and rising up again.
I need to count differencies between rows in new column and the sum of these differencies too (cumulative sum) for all values. The values 56 and 5 are new differencies from zero
The sum is 819.
Example from bottom> (23-2)+(43-23)+(109-43)+..+(654-643)+(5)+(23-5)+..
Okay, here is my try. However, you need to add an Identity field (which I called "AddSequence") that starts with 1 for the first value ("2") and increments by one for every other value.
SELECT SUM(C.Diff) FROM
(
SELECT CASE WHEN (A.[Value] - (SELECT [Value] FROM [TestValue] AS B WHERE B.[AddSequence]= A.[AddSequence]-1)) > 0
THEN (A.[Value] - (SELECT [Value] FROM [TestValue] AS D WHERE D.[AddSequence]= A.[AddSequence]-1))
ELSE 0
END AS Diff
FROM [TestValue] AS A
) AS C
The first solution I had neglected that fact that we had to start over whenever the difference was negative.
I think you are looking for something like:
SELECT SUM(a - b)) as sum_of_differences
FROM ...
I think you want this for the differences, I've tested it in sqlite
SELECT CASE WHEN (v.value - val) < 0 THEN 0 ELSE (v.value - val) END AS differences
FROM v,
(SELECT rowid, value AS val FROM v WHERE rowid > 1) as next_val
WHERE v.rowid = next_val.rowid - 1
as for the sums
SELECT SUM(differences) FROM
(
SELECT CASE WHEN (v.value - val) < 0 THEN 0 ELSE (v.value - val) END AS differences
FROM v,
(SELECT rowid, value AS val FROM v WHERE rowid > 1) AS next_val
WHERE v.rowid = next_val.rowid - 1
)
EDITED - BASED OFF OF YOUR QUESTION EDIT (T-SQL)
I don't know how you can do this without adding an Id.
If you ad an Id - this gives the exact output you had posted before your edit. There's probably a better way, but this is quick and dirty - for a one time shot. Using a SELF JOIN. Differences was the name of your new column originally.
UPDATE A
SET differences = CASE WHEN A.[values] > B.[Values] THEN A.[values] - B.[Values]
ELSE A.[values] END
FROM SO_TTABLE A
JOIN SO_TTABLE B ON A.ID = (B.ID - 1)
OUTPUT
Select [Values], differences FROM SO_TTABLE
[values] differences
------------------------
89 24
65 9
56 56
78 4
74 1
73 28
45 22
23 18
5 5
654 11
643 100
543 198
345 90
255 22
233 124
109 66
43 20
23 21
2 0