How to select row values for max(2 columns) - sql

I am working out a query in MS SQL Server. I have my table like this
Table( Level int, Stage int, values varchar)
Level Stage Value
1 1
1 2
1 3
2 1
2 2
I need to find the row having maximum value by level and then by stage. ie., I need to get the result as
Level Stage
2 2
When I try the below query I get the value 22 and in one column. I need that in 2 distinct columns as specified above.
SELECT MAX(CAST(wfLevel as varchar(2)) + CAST(approvalStage as varchar(2)))
FROM [AuditReporterDB].[dbo].[RequestHistory]
Can anyone help.

SELECT TOP 1 Level,Stage
FROM tableName
ORDER BY Level Desc,Stage Desc

Related

Keyset pagination with composite key

I am using oracle 12c database and I have a table with the following structure:
Id NUMBER
SeqNo NUMBER
Val NUMBER
Valid VARCHAR2
A composite primary key is created with the field Id and SeqNo.
I would like to fetch the data with Valid = 'Y' and apply ketset pagination with a page size of 3. Assume I have the following data:
Id SeqNo Val Valid
1 1 10 Y
1 2 20 N
1 3 30 Y
1 4 40 Y
1 5 50 Y
2 1 100 Y
2 2 200 Y
Expected result:
----------------------------
Page 1
----------------------------
Id SeqNo Val Valid
1 1 10 Y
1 3 30 Y
1 4 40 Y
----------------------------
Page 2
----------------------------
Id SeqNo Val Valid
1 5 50 Y
2 1 100 Y
2 2 200 Y
Offset pagination can be done like this:
SELECT * FROM table ORDER BY Id, SeqNo OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY;
However, in the actual db it has more than 5 millions of records and using OFFSET is going to slow down the query a lot. Therefore, I am looking for a ketset pagination approach (skip records using some unique fields instead of OFFSET)
Since a composite primary key is used, I need to offset the page with information from more than 1 field.
This is a sample SQL that should work in PostgreSQL (fetch 2nd page):
SELECT * FROM table WHERE (Id, SeqNo) > (1, 4) AND Valid = 'Y' ORDER BY Id, SeqNo LIMIT 3;
How do I achieve the same in oracle?
Use row_number() analytic function with ceil arithmetic fuction. Arithmetic functions don't have a negative impact on performance, and row_number() over (order by ...) expression automatically orders the data without considering the insertion order, and without adding an extra order by clause for the main query. So, consider :
select Id,SeqNo,
ceil(row_number() over (order by Id,SeqNo)/3) as page
from tab
where Valid = 'Y';
P.S. It also works for Oracle 11g, while OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY works only for Oracle 12c.
Demo
You can use order by and then fetch rows using fetch and offset like following:
Select ID, SEQ, VAL, VALID FROM TABLE
WHERE VALID = 'Y'
ORDER BY ID, SEQ
--FETCH FIRST 3 ROWS ONLY -- first page
--OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY -- second pages
--OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY -- third page
--Update--
You can use row_number analytical function as following.
Select id, seqNo, Val, valid from
(Select t.*,
Row_number(order by id, seq) as rn from table t
Where valid = 'Y')
Where ceil(rn/3) = 2 -- for page no. 2
Cheers!!

How to select string between two periods (SQL Server 2012)

Let's say I have a bunch of part numbers, and I want a column to return the string after the first period and before the second period. I looked at other similar questions but couldn't figure it out
So let's say I have of list of part numbers such as:
10416.1.1.4
10416.1.1.7
10416.1.1.1
10416.2.3
10416.2.2
10416.3.1.2
10416.3.1.3
10416.4.1.1
10416.10.1
10416.10.2
10416.11.1.1
I should have my column return:
1
1
1
2
2
3
3
4
10
10
11
Using SQL Server 2012, thanks in advance
Edit: Here's my code, this returns a table but the sorting is all over the place, the PartNo column is what I'm trying to split
SELECT DISTINCT OrderDet.OrderNo, Scheduling.JobNo, OrderDet.PartNo,
OrderDet.Priority
FROM Scheduling LEFT JOIN OrderDet ON Scheduling.JobNo = OrderDet.JobNo
WHERE Scheduling.WorkCntr = 'Glazing'
ORDER BY OrderDet.Priority DESC
You can use ParseName() in concert with Reverse()
Declare #YourTable Table ([SomeCol] varchar(50))
Insert Into #YourTable Values
('10416.1.1.4')
,('10416.1.1.7')
,('10416.1.1.1')
,('10416.2.3')
,('10416.2.2')
,('10416.3.1.2')
,('10416.3.1.3')
,('10416.4.1.1')
,('10416.10.1')
,('10416.10.2')
,('10416.11.1.1')
Select *
,NewCol = reverse(ParseName(reverse(SomeCol),2))
from #YourTable
Returns
SomeCol NewCol
10416.1.1.4 1
10416.1.1.7 1
10416.1.1.1 1
10416.2.3 2
10416.2.2 2
10416.3.1.2 3
10416.3.1.3 3
10416.4.1.1 4
10416.10.1 10
10416.10.2 10
10416.11.1.1 11

How to fetch the rows from SQL Server based on GROUP BY

How to fetch the rows from the top 2 pack id's not at a all of the rows in SQL Server?
Ex: Sample_table
tranid packid referencenum
1 1 123456
2 1 654982
3 2 894652
4 3 684521
5 3 684651
6 4 987566
Based on above sample table, how do I get the rows of pack 2 (for 1 and 2) for next instance I need again 3 and 4 rows
Can anyone help me out to sort the issue?
If I didn't miss something, this:
SELECT *
FROM PacksTable p
WHERE p.Id IN (1, 2)
Will give you only the data for the two pack_id's in your table.
It is unclear what you are looking for here. You can group by pack_id then get the top two pack_id, but what do you want to do with the grouped referencenum values for grouped pack_id, i.e What aggregate function you will use for this column, Min, Max, etc ??!.
In other words: If you are looking for the Top minimum pack_id, i.e.: 1, 2 in the first time, you will have to answer the question: What aggregate function to use with the corresponding referencenum values??,
For example, you can use MIN like this:
SELECT TOP(2) p.packid, MIN(p.referencenum)
FROM PacksTable p
GROUP BY(p.packid)
ORDER BY p.packid
please go through the following query.
select * from sample_table group by packid;
You could use variables combined with the DENSE_RANK function to window through two packid's at a time:
create table #packing (tranid int,packid int,referencenum int)
insert into #packing values
(1,1,123456)
, (2,1,654982)
, (3,2,894652)
, (4,3,684521)
, (5,3,684651)
, (6,4,987566)
go
declare #i int=-1;
declare #j int=0;
while ##ROWCOUNT>0 begin
set #i+=2;
set #j+=2;
; with a as (
select *, dr=dense_rank()over(order by packid) from #packing
)
select tranid, packid, referencenum
from a
where dr between #i and #j;
end
go
drop table #packing
go
Result:

Returning several rows from a single query, based on a value of a column

Let's say I have this table:
|Fld | Number|
1 5
2 2
And I want to make a select that retrieves as many Fld as the Number field has:
|Fld |
1
1
1
1
1
2
2
How can I achieve this? I was thinking about making a temporary table and instert data based on the Number, but I was wondering if this could be done with a single Select statement.
PS: I'm new to SQL
You can join with a numbers table:
SELECT Fld
FROM yourtable
JOIN Numbers
ON yourtable.Number <= Numbers.Number
A numbers table is just a table with a list of numbers:
Number
1
2
3
etc...
Not an great solution (since you still query your table twice, but maybe you can work from it)
SELECT t1.fld, t1.number
FROM table t1, (
SELECT ROWNUM number FROM dual
CONNECT BY LEVEL <= (SELECT MAX(number) FROM t1)) t2
WHERE t2.number<=t1.number
It generates maximum amount of rows needed and then filters it by each row.
I don't know if your RDBMS version supports it (although I rather suspect it does), but here is a recursive version:
WITH remaining (fld, times) as (SELECT fld, 1
FROM <table>
UNION ALL
SELECT a.fld, a.times + 1
FROM remaining as a
JOIN <table> as b
ON b.fld = a.fld
AND b.number > a.times)
SELECT fld
FROM remaining
ORDER BY fld
Given your source data table, it outputs this (count included for verification):
fld times
=============
1 1
1 2
1 3
1 4
1 5
2 1
2 2

SQL return multiple rows from one record

This is the opposite of reducing repeating records.
SQL query to create physical inventory checklists
If widget-xyz has a qty of 1 item return 1 row, but if it has 5, return 5 rows etc.
For all widgets in a particular warehouse.
Previously this was handled with a macro working through a range in excel, checking the qty column. Is there a way to make a single query instead?
The tables are FoxPro dbf files generated by an application and I am outputting this into html
Instead of generating an xml string and using xml parsing functions to generate a counter as Nestor has suggested, you might consider joining on a recursive CTE as a counter, as LukLed has hinted to:
WITH Counter AS
(
SELECT 0 i
UNION ALL
SELECT i + 1
FROM Counter
WHERE i < 100
),
Data AS
(
SELECT 'A' sku, 1 qty
UNION
SELECT 'B', 2
UNION
SELECT 'C', 3
)
SELECT *
FROM Data
INNER JOIN Counter ON i < qty
According to query analyzer, this query is much faster than the xml pseudo-table. This approach also gives you a recordset with a natural key (sku, i).
There is a default recursion limit of 100 in MSSQL that will restrict your counter. If you have quantities > 100, you can either increase this limit, use nested counters, or create a physical table for counting.
For SQL 2005/2008, take a look at
CROSS APPLY
What I would do is CROSS APPLY each row with a sub table with as many rows as qty has. A secondary question is how to create that sub table (I'd suggest to create an xml string and then parse it with the xml operators)
I hope this gives you a starting pointer....
Starting with
declare #table table (sku int, qty int);
insert into #table values (1, 5), (2,4), (3,2);
select * from #table;
sku qty
----------- -----------
1 5
2 4
3 2
You can generate:
with MainT as (
select *, convert(xml,'<table>'+REPLICATE('<r></r>',qty)+'</table>') as pseudo_table
from #table
)
select p.sku, p.qty
from MainT p
CROSS APPLY
(
select p.sku from p.pseudo_table.nodes('/table/r') T(row)
) crossT
sku qty
----------- -----------
1 5
1 5
1 5
1 5
1 5
2 4
2 4
2 4
2 4
3 2
3 2
Is that what you want?
Seriously dude... next time put more effort writing your question. It's impossible to know exactly what you are looking for.
You can use table with number from 1 to max(quantity) and join your table by quantity <= number. You can do it in many ways, but it depends on sql engine.
You can do this using dynamic sql.