How to select only the next smaller value - sql

I am trying to select smaller number from the database with the SQL.
I have table in which I have records like this
ID NodeName NodeType
4 A A
2 B B
2 C C
1 D D
0 E E
and other columns like name, and type.
If I pass "4" as a parameter then I want to receive the next smallest number records:
ID NodeName NodeType
2 B B
2 C C
Right now if I am using the < sign then it is giving me
ID NodeName NodeType
2 B B
2 C C
1 D D
0 E E
How can I get this working?

You can use WITH TIES clause:
SELECT TOP (1) WITH TIES *
FROM mytable
WHERE ID < 4
ORDER BY ID DESC
TOP clause in conjunction with WHERE and ORDER BY selects the next smallest value to 4. WITH TIES clause guarantees that all these values will be returned, in case there is more than one.
Demo here

select ID
from dbo.yourtable
where ID in
(
select top 1 ID
from dbo.your_table
where ID < 4
order by ID desc
);
Note: where dbo.your_table is your source table
What this does it uses an inner query to pull the next smallest ID below your selected value. Then the outer query just pulls all records that have that same match to the ID of the next smallest value.
Here's a full working example:
use TestDatabase;
go
create table dbo.TestTable1
(
ID int not null
);
go
insert into dbo.TestTable1 (ID)
values (6), (4), (2), (2), (1), (0);
go
select ID
from dbo.TestTable1
where ID in
(
select top 1 ID
from dbo.TestTable1
where ID < 4
order by ID desc
);
/*
ID
2
2
*/

Related

SSRS report column list sort order

Hi for my ssrs report i am using a matrix to display data row as a two column list and
I am using the following expression in order to group the row;
=ceiling(rownumber(nothing) / 2)
and
the following expression to group column;
=ceiling(rownumber(nothing) mod 2)
similar to https://www.experts-exchange.com/articles/12331/Simple-way-to-show-multi-column-data-in-SSRS-Horizontally-or-Vertically.html
it is working correctly however i would like results to be display alphabetical order going vertical instead of horizontal.
Like.
Record a Record d
Record b Record e
Record c Record f
Instead of
Record a Record b
Record c Record d
Record e Record f
i have order by in my sql query
any suggestions on how to achieve this?
You can modify your sql for this. The hack below could be used if you do not want to use multiple columns.
DECLARE #T TABLE
(
TableID INT,
Value1 NVARCHAR(20),
ShouldBe INT
)
INSERT INTO #T (TableID,Value1,ShouldBe)
VALUES
(1,'A',1),
(2,'B',3),
(3,'C',5),
(4,'D',2),
(5,'E',4),
(6,'F',6),
(7,'A',1),
(8,'B',3),
(9,'C',5),
(10,'D',2),
(11,'E',4),
(12,'F',6),
(13,'A',1)
DECLARE #NumberOfRowsPerPage INT = 3
DECLARE #NumberOfColumns INT = 2
SELECT PageNumber,Value1
FROM
(
SELECT ColumnOrder=ROW_NUMBER() OVER(PARTITION BY PageNumber,ColumnTile ORDER BY TableID),*
FROM
(
SELECT ColumnTile=NTILE(#NumberOfColumns) OVER(PARTITION BY PageNumber ORDER BY TableID),*
FROM
(
SELECT PageNumber=( (DataRowNumber -1) / (#NumberOfRowsPerPage * #NumberOfColumns )) + 1, *
FROM
(
SELECT DataRowNumber=ROW_NUMBER() OVER( ORDER BY TableID) ,*
FROM #T
)AS A
)AS B
)AS C
)AS D
ORDER BY
PageNumber,ColumnOrder,DataRowNumber
The query will produce the following output based on the RowsPerPage and NumberOfColumns.
Page Value
1 A
1 D
1 B
1 E
1 C
1 F
2 A
2 D
2 B
2 E
2 C
2 F
3 A

postgresql count the top 3 rows

I know we can use LIMIT in PostreSQL to get the top 3 values in the relation but what if there are duplicate values. For example,
5
4
4
3
2
Ordering it in DESC order and using LIMIT 3 will just return 5,4,4. But how do we get 5,4,4,3 (The top 3 with duplicates).
I know how to do this the long way but I was wondering if there are any PostreSQL built in things?
One easy way would be to use the dense_rank window function to rank the values as desired and then peel off those with the desired ranks.
For example, given this:
create table t (
id serial not null primary key, -- just a placeholder so that we can differentiate the duplicate `c`s.
c int not null
);
insert into t (c)
values (1), (1), (2), (3), (4), (4), (4), (5);
you'd presumably want the rows with c in (5,4,3) and you could do that with:
select id, c
from (
select id, c, dense_rank() over (order by c desc) as r
from t
) dt
where r <= 3
Demo: http://sqlfiddle.com/#!15/5b262/8
Note that you need to use dense_rank rather than rank because rank will arrange things in the right order but it will leave gaps in the rankings so r <= 3 wouldn't necessarily work. Compare the r values in the above fiddle with dense_rank and rank and you'll see the difference.
Suppose you have below record
index Name
1 "ABC"
2 "XYZ"
2 "ABC"
1 "XYZ"
1 "XYZ"
in this case you can distinct to choose non duplicate record.
Select distinct index, name from table_name;

Count value in output with normal rows

I have two tables named TEST and STEPS which are related by Test-Id column.
I am able to get all required columns by doing a join as below.
select t.id,t.name,s.step_no,s.step_data
from test t,steps s
where t.id = s.testid
What I require is that, apart fro the columns, I also need the total count of rows for each match.
Fiddle: http://sqlfiddle.com/#!6/794508/1
Current Output:
ID NAME STEP_NO STEP_DATA
-- ---- ------- ---------
1 TC1 1 Step 1
1 TC1 2 Step 2
1 TC1 3 Step 3
2 TC2 1 Step 1
Required Output:
ID NAME STEP_NO STEP_DATA COUNT
-- ---- ------- --------- -----
1 TC1 1 Step 1 3
1 TC1 2 Step 2 3
1 TC1 3 Step 3 3
2 TC2 1 Step 1 1
Where count is the total number of rows from the STEPS table for each Id in TEST table.
Please let me know if you need any information.
You could just add count(*) over ... to your query:
SELECT
t.id,
t.name,
s.step_no,
s.step_data,
[count] = COUNT(*) OVER (PARTITION BY s.testid)
FROM
test t,
steps s
WHERE
t.id = s.testid
You can read more about the OVER clause here:
OVER Clause (Transact-SQL)
Please consider also getting into the habit of
always specifying the schema for your tables, e.g.
test -> dbo.test
using the proper JOIN syntax, i.e. instead of
FROM
a, b
WHERE
a.col = b.col
do
FROM a
INNER JOIN b
ON a.col = b.col
ending your statements with a semicolon.
So, taking all those points into account, we could rewrite the above query like this:
SELECT
t.id,
t.name,
s.step_no,
s.step_data,
[count] = COUNT(*) OVER (PARTITION BY s.testid)
FROM
dbo.test AS t
INNER JOIN
dbo.steps AS s
ON
t.id = s.testid
;
select t.id,t.name,s.step_no,s.step_data,counts.count
from test t
join steps s ON t.id = s.testid
join (select testid, count(*) as count
from steps
group by testid) counts ON t.id = counts.testid
IS this works ....
DECLARE #test TABLE
(
id int identity primary key,
name varchar(20)
);
INSERT INTO #test VALUES('TC1'), ('TC2');
DECLARE #steps TABLE
(
id int identity primary key,
testid int,
step_no int,
step_data varchar(100)
);
INSERT INTO #steps(testid,step_no,step_data) VALUES
(1,1,'Step 1'), (1,2,'Step 2'),(1,3,'Step 3'),(2,1,'Step 1');
select t.id,t.name,s.step_no,s.step_data,(select SUM(testid) from #steps where testid = s.testid)
from #test t,#steps s
where t.id = s.testid

Select random row for each group

I have a table like this
ID ATTRIBUTE
1 A
1 A
1 B
1 C
2 B
2 C
2 C
3 A
3 B
3 C
I'd like to select just one random attribute for each ID. The result therefore could look like this (although this is just one of many options
ATTRIBUTE
B
C
C
This is my attempt on this problem
SELECT
"ATTRIBUTE"
FROM
(
SELECT
"ID",
"ATTRIBUTE",
row_number() OVER (PARTITION BY "ID" ORDER BY random()) rownum
FROM
table
) shuffled
WHERE
rownum = 1
however, I don't know if this is a good solution, as I need to introduce row numbers, which is a bit cumbersome.
Do you have a better one?
select distinct on (id) id, attribute
from like_this
order by id, random()
If you only need the attribute column:
select distinct on (id) attribute
from like_this
order by id, random()
Notice that you still need to order by id first as it is a column of the distinct on.
If you only want the distinct attributes:
select distinct attribute
from (
select distinct on (id) attribute
from like_this
order by id, random()
) s
Put a big random number in front of each record (id) and choose within each group the record with the lowest random number.
$ cat test.txt
\N 1 a
\N 2 b
\N 2 c
\N 2 d
\N 3 e
\N 4 f
$ mysql
USE test;
DROP TABLE test;
CREATE TABLE test (id0 INT NOT NULL AUTO_INCREMENT, id VARCHAR(1), attribute VARCHAR(1), PRIMARY KEY (id0));
LOAD DATA LOCAL INFILE '~/mysql/test.txt' INTO TABLE test FIELDS TERMINATED BY '\t';
DROP TABLE rtest;
CREATE TABLE rtest (random INT(8), id0 VARCHAR(1), id VARCHAR(1), attribute VARCHAR(1), PRIMARY KEY (id, random));
INSERT INTO rtest
SELECT CAST(1000000. * rand() AS INT) AS random, test.* FROM test;
SELECT rtest.* FROM rtest,
(SELECT id, min(random) AS random FROM rtest GROUP BY id) AS sample WHERE rtest.random=sample.random AND rtest.id=sample.id;

sql query logic

I have following data set
a b c
`1` 2 3
3 6 9
9 2 11
As you can see column a's first value is fixed (i.e. 1), but from second row it picks up the value of column c of previous record.
Column b's values are random and column c's value is calculated as c = a + b
I need to write a sql query which will select this data in above format. I tried writing using lag function but couldn't achieve.
Please help.
Edit :
Column b exists in table only, a and c needs to calculated based on the values of b.
Hanumant
SQL> select a
2 , b
3 , c
4 from dual
5 model
6 dimension by (0 i)
7 measures (0 a, 0 b, 0 c)
8 rules iterate (5)
9 ( a[iteration_number] = nvl(c[iteration_number-1],1)
10 , b[iteration_number] = ceil(dbms_random.value(0,10))
11 , c[iteration_number] = a[iteration_number] + b[iteration_number]
12 )
13 order by i
14 /
A B C
---------- ---------- ----------
1 4 5
5 8 13
13 8 21
21 2 23
23 10 33
5 rows selected.
Regards,
Rob.
Without knowing the relation between the rows ,how can we calculate the sum of the previous row a and b column to current row a column .I have created two more column id and parent in the table to find the relation between the two rows.
parent is the column which tell us about the previous row ,and id is the primary key of the row .
create table test1 (a number ,b number ,c number ,id number ,parent number);
Insert into TEST1 (A, B, C, ID) Values (1, 2, 3, 1);
Insert into TEST1 (B, PARENT, ID) Values (6, 1, 2);
Insert into TEST1 (B, PARENT, ID) Values (4, 2, 3);
WITH recursive (a, b, c,rn) AS
(SELECT a,b,c,id rn
FROM test1
WHERE parent IS NULL
UNION ALL
SELECT (rec.a+ rec.b) a
,t1.b b
,(rec.a+ rec.b+t1.b) c
,t1.id rn
FROM recursive rec,test1 t1
WHERE t1.parent = rec.rn
)
SELECT a,b,c
FROM recursive;
The WITH keyword defines the name recursive for the subquery that is to follow
WITH recursive (a, b, c,rn) AS
Next comes the first part of the named subquery
SELECT a,b,c,id rn
FROM test1
WHERE parent IS NULL
The named subquery is a UNION ALL of two queries. This, the first query, defines the starting point for the recursion. As in my CONNECT BY query, I want to know what is the start with record.
Next up is the part that was most confusing :
SELECT (rec.a+ rec.b) a
,t1.b b
,(rec.a+ rec.b+t1.b) c
,t1.id rn
FROM recursive rec,test1 t1
WHERE t1.parent = rec.rn
This is how it works :
WITH query: 1. The parent query executes:
SELECT a,b,c
FROM recursive;
This triggers execution of the named subquery. 2 The first query in the subquery's union executes, giving us a seed row with which to begin the recursion:
SELECT a,b,c,id rn
FROM test1
WHERE parent IS NULL
The seed row in this case will be for id =1 having parent is null. Let's refer to the seed row from here on out as the "new results", new in the sense that we haven't finished processing them yet.
The second query in the subquery's union executes:
SELECT (rec.a+ rec.b) a
,t1.b b
,(rec.a+ rec.b+t1.b) c
,t1.id rn
FROM recursive rec,test1 t1
WHERE t1.parent = rec.rn