Problems sorting data from SQL Server - sql

My problem is, to order these results in such a way that the order is as it is marked gray.
That is to say to obtain every first difference of the column EjeY.

Might be you are looking for this:
DECLARE #Dummy TABLE(ID INT IDENTITY, EjeY VARCHAR(100),Valor INT);
INSERT INTO #Dummy VALUES
('Alta/Deviciente',14)
,('Baja/Baja',16)
,('Baja/Media',14)
,('Alta/Alta',8)
,('Alta/Baja',12)
,('Baja/Deviciente',18)
,('Baja/Alta',12)
,('Alta/Optima',6)
,('Alta/Media',10)
,('Baja/Optima',10);
SELECT *
FROM #Dummy AS d
ORDER BY LEFT(EjeY,CHARINDEX('/',EjeY)-1),Valor DESC
The result
ID EjeY Valor
1 Alta/Deviciente 14
5 Alta/Baja 12
9 Alta/Media 10
4 Alta/Alta 8
8 Alta/Optima 6
6 Baja/Deviciente 18
2 Baja/Baja 16
3 Baja/Media 14
7 Baja/Alta 12
10 Baja/Optima 10

If you only want to record the changes in the left part of your Ejey delimited field then you need to split the field and then order rank the values by ID.
After you have a ranking you can select the records you are interested in taking the first row of the PARTITION.
DECLARE #Dummy TABLE(ID INT, EjeY VARCHAR(100),Valor INT);
INSERT INTO #Dummy VALUES
(1,'Alta/Deviciente',14)
,(2,'Alta/Baja',12)
,(6,'Baja/Optima',10)
,(7,'Baja/Alta',12)
,(11,'Deficiente/Deficiente',20)
,(11,'Deficiente/Baja',18)
,(16,'Media/Alta',10)
,(17,'Media/Optima',8)
--This query will draw a rank in your data based on the LEFT() partition of your Ejey field value.
SELECT
*,
RowNumber=ROW_NUMBER() OVER(PARTITION BY SortPart ORDER BY ID DESC)
FROM
(
SELECT
ID,
SortPart=LEFT(EjeY,CHARINDEX('/',EjeY)-1),
Valor
FROM
#Dummy
)AS X
--This query will further order only the records within your ideal set of data
SELECT
*
FROM
(
SELECT
*,
RowNumber=ROW_NUMBER() OVER(PARTITION BY SortPart ORDER BY ID ASC)
FROM
(
SELECT
ID,
SortPart=LEFT(EjeY,CHARINDEX('/',EjeY)-1),
Valor
FROM
#Dummy
)AS X
)AS Y
WHERE
RowNumber=1
--Results A
ID SortPart Valor RowNumber
2 Alta 12 1
1 Alta 14 2
7 Baja 12 1
6 Baja 10 2
11 Deficiente 20 1
11 Deficiente 18 2
17 Media 8 1
16 Media 10 2
--Results B
ID SortPart Valor RowNumber
1 Alta 14 1
6 Baja 10 1
11 Deficiente 20 1

Related

offset does not work with Count(*) as order by

I have a query with Count(*) as order by with offset fetch next. When I am using different values as offset it is always providing the same resultset.
I tried with some column as order by where the resultset varies and it worked perfectly fine. Can someone help with this.
select
Id,
count(*) as "Count"
from
some_table
group by
"Id"
Order By
"Count" ASC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY;
Screenshot 1
Screenshot 2
This is your query:
select Id, count(*) as "Count"
from some_table
group by "Id"
order by "Count" asc
OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY;
The problem is that you have duplicate values for count(*). Because SQL tables represent unordered sets, it has no default ordering. That poses a problem when sort keys have the same value.
The simple solution is to include id in the order by:
order by "Count" asc, id
This makes the sort stable, so it is well-defined.
here is the My example
Create a Table
create table t (id int, name varchar(100))
insert data's
insert into t values(1,'saravnan')
insert into t values(1,'kumar')
insert into t values(1,'Ravi')
insert into t values(1,'mohan')
insert into t values(2,'Raju')
insert into t values(2,'Vikram')
insert into t values(2,'AA')
insert into t values(2,'BB')
insert into t values(2,'CC')
insert into t values(2,'DD')
insert into t values(2,'EE')
insert into t values(3,'Raju')
insert into t values(3,'Vikram')
insert into t values(3,'AA')
insert into t values(4,'BB')
insert into t values(4,'CC')
insert into t values(4,'DD')
insert into t values(4,'EE')
select all data
select *from t
id name
1 1 saravnan
2 1 kumar
3 1 Ravi
4 1 mohan
5 2 Raju
6 2 Vikram
7 2 AA
8 2 BB
9 2 CC
10 2 DD
11 2 EE
12 3 Raju
13 3 Vikram
14 3 AA
15 4 BB
16 4 CC
17 4 DD
18 4 EE
offset is used for Number of rows skip from start of the table data. it should be number.
here my example:
select id,count(*) from t group by id order by id offset 1 rows fetch next 3 row only
It returns
id count
1 2 7
2 3 3
3 4 4
The fetch next used for number rows to return.
Solution for your example .
--offset 0 returns[enter image description here][1]
select Id,count(1) as "Count" from t group by ID Order By "Count" ASC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY
Id Count
1 3 3
2 4 4
3 1 4
4 2 7
-- offset 1 returns
select Id,count(1) as "Count" from t group by ID Order By "Count" ASC OFFSET 1 ROWS FETCH NEXT 5 ROWS ONLY
Id Count
1 4 4
2 1 4
3 2 7

Highest per each group

It's hard to show my actual table and data here so I'll describe my problem with a sample table and data:
create table foo(id int,x_part int,y_part int,out_id int,out_idx text);
insert into foo values (1,2,3,55,'BAK'),(2,3,4,77,'ZAK'),(3,4,8,55,'RGT'),(9,10,15,77,'UIT'),
(3,4,8,11,'UTL'),(3,4,8,65,'MAQ'),(3,4,8,77,'YTU');
Following is the table foo:
id x_part y_part out_id out_idx
-- ------ ------ ------ -------
3 4 8 11 UTL
3 4 8 55 RGT
1 2 3 55 BAK
3 4 8 65 MAQ
9 10 15 77 UIT
2 3 4 77 ZAK
3 4 8 77 YTU
I need to select all fields by sorting the highest id of each out_id.
Expected output:
id x_part y_part out_id out_idx
-- ------ ------ ------ -------
3 4 8 11 UTL
3 4 8 55 RGT
3 4 8 65 MAQ
9 10 15 77 UIT
Using PostgreSQL.
Postgres specific (and fastest) solution:
select distinct on (out_id) *
from foo
order by out_id, id desc;
Standard SQL solution using a window function (second fastest)
select id, x_part, y_part, out_id, out_idx
from (
select id, x_part, y_part, out_id, out_idx,
row_number() over (partition by out_id order by id desc) as rn
from foo
) t
where rn = 1
order by id;
Note that both solutions will only return each id once, even if there are multiple out_id values that are the same. If you want them all returned, use dense_rank() instead of row_number()
select *
from foo
where (id,out_id) in (
select max(id),out_id from foo group by out_id
) order by out_id
Finding max(val) := finding the record for which no larger val exists:
SELECT *
FROM foo f
WHERE NOT EXISTS (
SELECT 317
FROM foo nx
WHERE nx.out_id = f.out_id
AND nx.id > f.id
);

SQL - Add value with previous row only

I have a table named myvals with the following fields:
ID number
-- -------
1 7
2 3
3 4
4 0
5 9
Starting on 2nd row, I would like to add the number with the previous row number. So, my end result would look like this
ID number
-- ------
1 7
2 10
3 7
4 4
5 9
You could use the LAG analytic function
SELECT Id, number + LAG(number,1,0) OVER (ORDER BY Id) FROM table
First thing's first. You can't add to null to ID 1 must have a value.
create table #temp
(
month_type datetime,
value int
)
insert into #temp
Select '2015/01/01',1
union
Select '2015/02/01',2
union
Select '2015/03/01',3
union
Select '2015/04/01',4
SELECT t.value,t1.value,(t.value+t1.value)/2 FROM #temp t1
left join #temp t on t.month_type=Dateadd(MONTH,-1,t1.month_type)

SQL RANDOM ORDER BY ON JOINED TABLE

I have 2 tables: Persons(idPerson INT) and Questions(idQuestion INT).
I want to insert the data into a 3rd table: OrderedQuestions(idPerson INT, idQuestion INT, questionRank INT)
I want to assign all the questions to all the persons but in a random order.
I thought of doing a CROSS JOIN but then, I get the same order of questions for every persons.
INSERT INTO OrderedQuestions
SELECT idPerson, idQuestion, questionRank FROM Persons
CROSS JOIN
(SELECT idQuestion,ROW_NUMBER() OVER (ORDER BY NEWID()) as questionRank
FROM Questions) as t
How can I achieve such a random, distinct ordering for every persons?
Obviously, I want the solution to be as fast as possible.
(It can be done using TSQL or Linq to SQL)
Desired results for 3 persons and 5 questions:
idPerson idQuestion questionRank
1. 1 18 1
2. 1 14 2
3. 1 25 3
4. 1 31 4
5. 1 2 5
6. 2 2 1
7. 2 25 2
8. 2 31 3
9. 2 18 4
10. 2 14 5
11. 3 31 1
12. 3 18 2
13. 3 14 3
14. 3 25 4
15. 3 2 5
I just edited the results (Since the IDs are autogenerated, they can't be used to order the questions).
This could probably be written more efficently, but it meets all the reqs.
SELECT
idperson,
idQuestion,
ROW_NUMBER() OVER (PARTITION BY personid ORDER BY ordering) as questionRank
FROM (
SELECT idperson, idQuestion, ordering
FROM person
CROSS JOIN
(
SELECT idQuestion, NewID() as ordering FROM Question
) as t
) as a
order by personid, QuestionRank

Select all items with sum of fields in specified range

I have simple table:
file_size file_id file_time
1 1 19
2 2 20
3 3 21
4 4 22
5 5 23
I want to find such item that all items with less file_time has the sum of file_size in predefined range.
I written next query:
SELECT * FROM test_table AS D0 WHERE
(SELECT TOTAL(file_size) FROM test_table AS D1 WHERE
D1.file_time <= D0.file_time ORDER BY file_id)
BETWEEN 1 AND 9
This query get correct results:
1 1 19
2 2 20
3 3 21
But this query does not work if needed items has the same file_time field:
file_size file_id file_time
1 1 20
2 2 20
3 3 20
4 4 20
5 5 20
The desired result for this data is:
1 1 20
2 2 20
3 3 20
The file_id field is unique.
What is wrong in my SQL-query?
The code to create test table:
CREATE TABLE test_table (file_size INT, file_id INT, file_time INT)
INSERT INTO test_table VALUES(1,1,20)
INSERT INTO test_table VALUES(2,2,20)
INSERT INTO test_table VALUES(3,3,20)
INSERT INTO test_table VALUES(4,4,20)
INSERT INTO test_table VALUES(5,5,20)
You shouldn't consider file_time as a single column in your query, since you want to consider the column file_id either. You should use the pairs of file_time and file_id and you should compare them lexicographically as follows:
SELECT *
FROM test_table AS D0
WHERE (
SELECT TOTAL( file_size )
FROM test_table AS D1
WHERE D1.file_time < D0.file_time
OR (
D1.file_time = D0.file_time
AND D1.file_id <= D0.file_id
)
ORDER BY file_time, file_id DESC
)
BETWEEN 1
AND 9
Not sure if I understood but I think
-- sum of file sizes between 1 and 7 with the lowest time
SELECT SUM(test.file_size) AS sum_file_size, test.file_time
FROM test
WHERE (test.file_time = (SELECT TOP 1 test.file_time
FROM test
ORDER BY file_time))
AND (test.file_size BETWEEN 1 AND 9)
GROUP BY test.file_time;
-- sum of file sizes per time `group`
SELECT SUM(test.file_size) AS sum_file_size, test.file_time,
FROM test
WHERE (test.file_size BETWEEN 1 AND 7)
GROUP BY test.file_time
ORDER BY test.file_time;