Order by newly selected column - sql

I have a query like:
SELECT
R.*
FROM
(SELECT A, B,
(SELECT smth from another table) as C,
ROW_NUMBER() OVER (ORDER BY C DESC) AS RowNumber
FROM SomeTable) R
WHERE
RowNumber BETWEEN 10 AND 20
This gives me an error on ORDER BY C DESC.
I understand why this error is caused, so I've thought of adding another SELECT with ORDER BY and only than selecting rows from 10 to 20. But I don't think it's good to have 3 nested SELECT commands.
How else is it possible to select these rows?

A column cannot refer to an alias on same level, you have to table-derive it first, or use CTE.
SELECT
R.* , ROW_NUMBER() OVER (ORDER BY C DESC) AS RowNumber
FROM
(SELECT A, B, (SELECT smth from another table) as C
FROM SomeTable) R
-- WHERE
-- but you still cannot do this
-- RowNumber BETWEEN 10 AND 20
Need to do this:
select S.*
from
(
SELECT
R.* , ROW_NUMBER() OVER (ORDER BY C DESC) AS RowNumber
FROM
(SELECT A, B,
(SELECT smth from another table) as C
FROM SomeTable) R
) as s
where s.RowNumber between 10 and 20
To avoid deep nesting and to make it at least look pleasant, use CTE:
with R as
(
SELECT A, B, (SELECT smth from another table) as C
FROM SomeTable
)
,S AS
(
SELECT R.*, ROW_NUMBER() OVER (ORDER BY C DESC) AS RowNumber
FROM R
)
SELECT S.*
FROM S
WHERE S.RowNumber BETWEEN 1 AND 20

You cannot use aliased columns in the same SELECT, but you can wrap it into another select to make it work:
SELECT R.*
FROM (SELECT ABC.A, ABC.B, ABC.C, ROW_NUMBER() OVER (ORDER BY C DESC) AS RowNumber
FROM (SELECT A, B, (SELECT smth from another table) as C FROM SomeTable) ABC
) R
WHERE R.RowNumber BETWEEN 10 AND 20

Related

Random allocation of records between two tables

I want to assign the values from Table B to Table A, but so that each record in Table B occurs in the same number of repetitions.
Fiddle SQL
You can use window functions for this and mod arithmetic. For simple repetition:
with a as (
select a.*, rownum as seqnum
from a
),
b as (
select b.*, rownum as seqnum, count(*) over () as cnt
from b
)
select a.col, b.col
from a join
b
on mod(a.seqnum - 1, b.cnt) = b.seqnum - 1;
For more random assignment, randomize the seqnums:
with a as (
select a.*,
row_number() over (order by dbms_random.random) as seqnum
from a
order by db
),
b as (
select b.*, count(*) over () as cnt,
row_number() over (order by dbms_random.random) as seqnum
from b
)
select a.col, b.col
from a join
b
on mod(a.seqnum - 1, b.cnt) = b.seqnum - 1;
You can use the ROWNUM for achieving the same:
SELECT
COLOUR,
EMP
FROM
(
SELECT
COLOUR,
ROWNUM RN
FROM
T1
) T1,
(
SELECT
EMP,
ROWNUM RN
FROM
T2
) T2
WHERE
MOD(T1.RN, 2) + 1 = T2.RN
Fiddler SQL QUERY
Try this,
with Employees as
(select Emp, Row_Number() Over(order by 1) Rn
from B
cross join (select 1
from Dual
connect by level < (select count(1)
from A) / (select count(1)
from B) + 1)
order by Dbms_Random.Value),
Colours as
(select Colour, Rownum Rn
from A)
select t.Colour, k.Emp
from Colours t
join Employees k
on t.Rn = k.Rn

SQL SELECT DISTINCT CONCAT(ColumnA,'|',ColumnB)

So I have two tables and I want to use a concat on one of the columns in each table.
TableA
ColumnA
1
1
2
3
4
4
5
TableB
ColumnX
a
a
b
c
d
d
e
And I want to concat these two columns so they end up looking like the below result WITHOUT dublicates
Result
1|a
2|b
3|c
4|d
5|e
So I have tried to do the following:
SELECT DISTINCT CONCAT(ColumnA,'|',ColumnB) where tableA.Relation = TableB.Relation
But I am still getting dublicates!? Why????
you could generate the row_numbers by row_numbers() function & then concat them (SQL Server)
;with cte as
(
SELECT *, ROW_NUMBER() over (order by (select 1)) rn FROM <table>
),cte1 as
(
SELECT *, ROW_NUMBER() over (order by (select 1)) rn FROM <table>
)
select DISTINCT CONCAT(c.ColumnA, '|',c1.ColumnX) from cte c
join cte1 c1 on c1.rn = c.rn
This is similar only without the CTE
select distinct A.a + '|' + B.b
from
(select a, Row_Number() over (order by a) as rowNum
from TableA) as A,
(select b, Row_Number() over (order by b) as rowNum
from TableB) as B
where A.rowNum = b.rowNum

Select MAX(DateTime) returning multiple lines

I'm trying to select the last MAX(DateTime) status from the table "Zee" but if the DateTime is the same it returns two lines, and I would like to get only the last one (maybe last inserted?).
here is the query:
SELECT Z."ID" AS ID,Z."A" AS A,Z."B" AS B,Z."C" AS C,Z."D" AS D
FROM ZEE Z
INNER JOIN
(SELECT ID, A, B, MAX(C) AS C
FROM ZEE
GROUP BY A, B) groupedtt
ON Z.A = groupedtt.A
AND Z.B = groupedtt.B
AND Z.C = groupedtt.C
WHERE (
Z.B = 103
OR Z.B = 104
);
and the result:
Thanks,
Regards.
I usually use rank() for such things:
select Z."ID" AS ID,Z."A" AS A,Z."B" AS B,Z."C" AS C,Z."D" AS D
from (select Z.*, rank()over(partition by A,B order by C desc, rownum) r from ZEE Z
)Z where Z.r=1
Use the ROW_NUMBER() analytic function (you will also eliminate the self-join):
SELECT ID, A, B, C, D
FROM (
SELECT ID,
A,
B,
C,
D,
ROW_NUMBER() OVER ( PARTITION BY A, B ORDER BY C DESC ) As rn
FROM ZEE
)
WHERE rn = 1;

Some need help on SQL statement

Assume the following table:
Select *
from TestTable;
Name value
B 3
C 1
A 2
I want to output as follows:
Name value
A 1
B 2
C 3
Notice that in the result Names are matched to their corresponding ordinal values from the value column.
Anyone help, how can I write the SQL statement?
select
Name, Value
from
-- Order the Name table
(select row_number() over (order by name) as id, Name from TestTable) as n
inner join
-- Order the Value table
(select row_number() over (order by value) as id, Value from TestTable) as v
on n.id = v.id -- Combine two table by the ordered id
SELECT A.Name, B.Value FROM (
SELECT ROW_NUMBER() OVER(ORDER BY Name) as N, Name FROM Tab ) as A
INNER JOIN (SELECT ROW_NUMBER() OVER(ORDER BY Value) as N, Value FROM Tab) as B on B.N = A.N
WITH
test1 AS
(SELECT ROW_NUMBER() over(order by Name)as id , Name FROM Testing ),
test2 AS
(SELECT ROW_NUMBER() over(order by value)as id , value FROM Testing )
SELECT Name,Value
FROM test1
JOIN test2
ON test1.id=test2.id

In SQL in a "group by" expression: how to get the string that occurs most often in a group?

Assume we have the following table:
Id A B
1 10 ABC
2 10 ABC
3 10 FFF
4 20 HHH
As result of a "group by A" expression I want to have the value of the B-Column that occurs most often:
select A, mostoften(B) from table group by A;
A mostoften(B)
10 ABC
20 HHH
How do I achieve this in Oracle 10g?
Remark: in the case of a tie (when there are more than one value that occurs most often) it does not matter which value is selected.
select A, B
from (
select A, B, ROW_NUMBER() OVER (PARTITION BY A ORDER BY C_B DESC) as rn
from (
select A, COUNT (B) as C_B, B
from table
group by A, B
) count_table
) order_table
where rn = 1;
You want the Bs with the MAX of COUNT group by A, B.
Old school solution, it took me some time and some cursing :)
select a,b
from ta ta1
group by a,b
having count(*) = (select max(count(*))
from ta ta2
where ta1.a = ta2.a
group by b)
This problem can be clarified by creating a view for the count in each A & B group:
CREATE VIEW MyTableCounts AS
SELECT A, B, COUNT(*) C
FROM MyTable
GROUP BY A, B;
Now we can do a query that finds the row c1 where the count is greatest. That is, no other row that has the same A has a greater count. Therefore if we try to find a row c2 with a greater count, no match is found.
SELECT c1.A, c1.B
FROM MyTableCounts c1
LEFT OUTER JOIN MyTableCounts c2
ON (c1.A = c2.A AND (c1.C < c2.C OR (c1.C = c2.C AND c1.B < c2.B)))
WHERE c2.A IS NULL
ORDER BY c1.A;
To resolve tied counts (c1.C = c2.C), we use the value of B which we know is unique within a given group of A.
try this (works on SQL Server 2005):
declare #yourtable table (rowid int, a int,b char(3))
insert into #yourtable values (1,10,'ABC')
insert into #yourtable values (2,10,'ABC')
insert into #yourtable values (3,10,'FFF')
insert into #yourtable values (4,20,'HHH')
;WITH YourTableCTE AS
(
SELECT
*, ROW_NUMBER() OVER(partition by A ORDER BY A ASC,CountOfB DESC) AS RowRank
FROM (SELECT
A, B, COUNT(B) AS CountOfB
FROM #yourtable
GROUP BY A,B
) dt
)
SELECT
A,B
FROM YourTableCTE
WHERE RowRank=1
EDIT without CTE...
SELECT
A,B
FROM (SELECT
*, ROW_NUMBER() OVER(partition by A ORDER BY A ASC,CountOfB DESC) AS RowRank
FROM (SELECT
A, B, COUNT(B) AS CountOfB
FROM #yourtable
GROUP BY A,B
) dt
) dt2
WHERE RowRank=1