SQL Server 2008 - Getting specific rows like 200-300 - sql

I have a SQL Server table called pluginProspects and I have the following columns..
FirstName
LastName
Email
AmonutOfEmployees
AnnualRevenue
In this table I have thousand of rows, and I wanted to create a SQL statement that allows me to retrieve rows 200 - 300 or even rows 300 - 400 or w/e I want.
I use to use this following code which worked for a while, BUT I want to add specific WHERE clause and its not showing me hundred results, its showing me like 50 or 70 or w/e depending on the results from those specific row numbers
SELECT *
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY demoID DESC) AS rownum,
demoID, RecordStatus, Email, FirstName, LastName, AmountOfEmployees,
AnnualRevenue
FROM
pluginProspects) AS Salaries1
WHERE
rownum BETWEEN 1 * {STARTNUMBERHERE} - 100 AND 1 * {STARTNUMBERHERE}
AND (RecordStatus = '2014 Lead')
AND (AmonutofEmployees > 10)
ORDER BY
AmountOfEmployees DESC
As you can see {STARTNUMBERHERE} I could put 100, 200, 300, 400 etc to create a paging effect which worked perfectly fine UNTIL I added (AmountofEmployees > 10)
Well in my table there tons of prospects that have less than 10 employees, so this will sometimes only show 10 or 20 results, instead of the first 100 results.
Anyone know the correct way I should be doing this? No I can't use a stored procedure for what I'm trying to do, it has to be pure SQL based

Matt,
Max meant to change it to look like this
SELECT *
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY demoID DESC) AS rownum,
demoID, RecordStatus, Email, FirstName, LastName, AmountOfEmployees,
AnnualRevenue
FROM
pluginProspects
WHERE (RecordStatus = '2014 Lead')
AND (AmonutofEmployees > 10) ) AS Salaries1
WHERE
rownum BETWEEN 1 * {STARTNUMBERHERE} - 100 AND 1 * {STARTNUMBERHERE}
ORDER BY
AmountOfEmployees DESC

Related

how to select SQL , age 20 first , and then all the rest from table PERSONS?

My table contains 113 people.
48 of them are 20 years old. Now I am just selecting all people like
select * from persons
this will get me all persons, but 20 yr old are not the first 48 people.
I need the 20 yr old to be first 48 in 113 results.
something like
20 year ols ( 48 of them ), after that ..... all the rest in the table
How can I query this using PostgreSQL.
EDIT : there are age less than 20 too. after getting the first 48 , 20 yr olds, I dont care rest of the order I am getting the 48 to 113 people.
Just use order by :
select *
from persons
order by age
You can use asc or desc but because default is asc you do not need to put it in your example.
select *
from persons
order by age desc
After the comment from OP here is the new code(I do not know why but my firs assumption was that the value 20 is the lowest possible value... bad assumption):
select *
from persons
order by case when age = 20 then 1 else 2 end
OR
select *
from persons
order by (age = 20) desc
Here is a demo
If 20 is not your minimum age, you can use the CASE statement inside the ORDER BY clause, like this:
SELECT
*
FROM
persons
ORDER BY
CASE WHEN age = 20 THEN 0
ELSE 1
END ASC

Nested Query in EF6

I have a query which I like to use for paging. With dapper I am able to take the query below and use SplitOn which allows me to separate the results on the left side of SplitOn column into one object and results of the right side of SplitOn column into a second object. What this allows me to do is get a total records count along with records for "specified" pages only
SELECT *
FROM (
SELECT
*,1 as SplitOn,
(ROW_NUMBER() OVER(ORDER BY Id )) AS RowNum, COUNT(*) over() as TotalRows
FROM (
SELECT Id, FirstName, LastName FROM Customer
) AS FirstQuery
) AS TEMP
WHERE RowNum BETWEEN 1 + ((#Page - 1) * #PageSize) AND #Page * #PageSize
If you run above in SQL for page 6 you will get:
Id FirstName LastName SplitOn RowNum TotalRows
61 John Luke 1 1 120
62 Jane Sky 1 2 120
63 Boby Doe 1 3 120
64 Sam Ace 1 4 120
65 Dany Table 1 5 120
etc...
I am trying to accomplish the same with EF6 but I cannot for the life of me figure out how to convert that query to an equivalent LinQ Expression.
I realize that SplitOn may not be possible with EF6, so I can work around that with a single object, but I still cannot figure out how to make my query with LinQ.

MS Access equivalent for using dense_rank in select

In MS Access, I have a table with 2 million account records/rows with various columns of data. I wish to apply a sequence number to every account record. (i.e.- 1 for the first account record ABC111, 2 for the second account record DEF222..., etc.)
Then, I would like to assign a batch number sequence for every 5 distinct account number. (i.e - record 1 with account number ABC111 being associated with batch number 101, record 2 with account number DEF222 being associated with batch number of 101)
This is how I would do it with a sql server query:
select distinct(p.accountnumber),FLOOR(((50 + dense_rank() over(order by
p.accountnumber)) - 1)/5) + 100 As BATCH from
db2inst1.account_table p
Raw Data:
AccountNumber
ABC111
DEF222
GHI333
JKL444
MNO555
PQR666
STU777
Resulting Data:
RecordNumber AccountNumber BatchNumber
1 ABC111 101
2 DEF222 101
3 GHI333 101
4 JKL444 101
5 MNO555 101
6 PQR666 102
7 STU777 102
I tried to make a query that uses SELECT as well as DENSE_RANK but I couldn't figure out how to make it work.
Thanks for reading my question
Something like this would probably work.
I'd first create a temporary table to hold the distinct account numbers, then I'd do an update query to assign the ranking.
CREATE TABLE tmpAccountRank
(AccountNumber TEXT(10)
CONSTRAINT PrimaryKey PRIMARY KEY,
AccountRank INTEGER NULL);
Then I'd use this table to generate the account ranking.
DELETE FROM tmpAccountRank;
INSERT INTO tmpAccountRank(AccountNumber)
SELECT DISTINCT AccountNumber FROM db2inst1.account_table;
UPDATE tmpAccountRank
SET AccountRank =
DCOUNT('AccountNumber', 'tmpAccountRank',
'AccountNumber < ''' + AccountNumber + '''') \ 5 + 101
I use DCOUNT and integer division (\ 5) to generate the ranking. This probably will have terrible performance but I think it's the way you would do it in MS Access.
If you want to skip the temp table, you can do it all in a nested subquery, but I don't think it's a great practice to do too much in a single query, especially in MS Access.
SELECT AccountNumber,
(SELECT COUNT(*) FROM
(SELECT DISTINCT AccountNumber
FROM db2inst1.account_table
WHERE AccountNumber < t.AccountNumber) q)) \ 5 + 101
FROM db2inst1.account_table t
Actually, this won't work in MS Access; apparently you can't reference tables outside of multiple levels of nesting in a subquery.
You can do dense_rank() with a correlated subquery. The logic is:
select a.*,
(select count(distinct a2.accountnumber)
from db2inst1.account_table as a2
where a2.accountnumber <= a.accountnumber
) as dense_rank
from db2inst1.account_table as a;
Then, you can use this for getting the batch number. Unfortunately, I don't follow the logic in your question (dense_rank() produces a number but your batch number is not numeric). However, this should answer your question.
EDIT:
Oh, that's right. In MS Access you need nested subqueries:
select a.*,
(select count(*)
from (select distinct a2.accountnumber
from db2inst1.account_table as a2
) as a2
where a2.accountnumber <= a.accountnumber
) as dense_rank
from db2inst1.account_table as a;

SQL query to select min date

I have a SQL table called transaction where different type of transactions are stored e.g. Payment arrangements, sent letter and so on.
I have ran a query:
SELECT TOP 6 Case_Ref as Case Ref,TrancRefNO as Tranc RefNO, Date_CCYYMMDD, LetterSent, Arr_Freq,
SMS_Sent_CCYYMMDD
From Transaction
Where (LEN(LetterSent ) >0 OR Arr_Freq >0)
The table looks something like this
Case Ref Tranc RefNO Date_CCYYMMDD LetterSent Arr_Freq SMS_Sent_CCYYMMDD
-------- ----------- ---------- ---------- ---------- -----------------
15001 100 20140425 Stage1
15001 101 20140430 Stage2
15001 102 20140510 30
15001 104 20140610 30
15002 105 20140425 Stage1
15002 106 20140610 30
From the table, I can clearly see that a letter was sent on '20140430' for the case 15001 and the person started arrangements on '20140510'. And a letter was sent on '20140425' for the case 15001 and the person made arrangements on on '20140610'.
I'm trying to create a excel report using C# which will show the total number of cases got arrangements after getting a letter and total number of cases for arrangements after receiving a SMS.
I have tried
select MAX(ROW_NUMBER() OVER(ORDER BY o3.Date_CCYYMMDD ASC)), o3.
from
(
select o.TrancRefNO, o.Date_CCYYMMDD , sq.LetterSent
from Transaction o
join Transaction sq on sq.TrancRefNO= o.TrancRefNO
and sq.Date_CCYYMMDD <= o.Date_CCYYMMDD
where o.Arr_Freq >0
and len(sq.LetterSent ) > 0
) o2
join Transaction o3 on o3.TrancRefNO= o2.TrancRefNO
But gives me an error :
Msg 4109, Level 15, State 1, Line 2
Windowed functions cannot be used in the context of another windowed function or aggregate.
P.s Title will need to be changed as I don't know what to call it.
SELECT * FROM table as t1
WHERE (LetterSent != '' OR SMS_SENT_CCYYMMDD != '')
AND (SELECT COUNT(*) FROM table AS t2
WHERE t1.case_ref = t2.case_ref
AND t1.DATE_CCYYMMDD < t2.DATE_CCYYMMDD
AND Arr_freq > 0) > 1
My assumptions based on what I could glean from your post:
ARR_FREQ!='' indicates that some time of arrangement was made at the specified date
Since NULL is not shown, I'm assuming all values are ''. With null values you will have to use a coalesce command
Hope this helps. I'm not sure about your second question (max date) in the comments. You would need to explain it a bit more.
SELECT TOP 1 ROW_NUMBER() OVER(ORDER BY Date_CCYYMMDD ASC), mytable.*
FROM mytable
or just
SELECT TOP 1 * FROM mytable
ORDER BY Date_CCYYMMDD ASC
but i guess, you want to get not the MIN date overall, but group by first
SELECT * FROM table where Date =
(SELECT MIN(Date) from table)

Select Rows in a uniform order

I have a table customer and 100 rows in it. a status column is set for active/inactive customer in the table.
What i want to do is to select all customers from the table in a specific order
ie
first 7 active customers then 3 inactive customers again 7 active customers and 3 inactive and so on
How can I achieve this in a query.
I am using sql server 2008 . Please Help me....
Something like this should do it, based on the minimal requirements you've listed so far:
;with NumberedRows as (
select
*, --TODO - pick columns
ROW_NUMBER() OVER(PARTITION BY status ORDER BY PKID) - 1 as rn
from
table
), AlteredOrdering as (
select
*, --TODO - pick columns
CASE
WHEN status = 'active' THEN (10 * (rn/7)) + (rn % 7)
WHEN status = 'inactive' THEN (10 * (rn/3)) + 7 + (rn % 3)
END as FinalOrder
from NumberedRows
)
select * from AlteredOrdering ORDER BY FinalOrder
Obviously, altering the table and column names as appropriate. PKID is assumed to be some other column in the table against which the individual rows can be ordered.
The magic numbers in the AlteredOrdering CTE are hopefully obvious - 7 and 3 come from the question, and represent how many of each item should appear in each "group". The 10 is the total size of each "group". So if it was 9 active, 4 inactive, the CASE expression would look like:
WHEN status = 'active' THEN (13 * (rn/9)) + (rn % 9)
WHEN status = 'inactive' THEN (13 * (rn/4)) + 9 + (rn % 4)
As far as I am aware you cannot. It would likely require processing of the data once you had retrieved it from SQL
if you have only 100 rows then perhaps limit x,y combine with union can help
select * from table where status=active limit 0,7
union
select * from table where status=inactive limit 7,3
union
select * from table where status=active limit 10,7
union
select * from table where status=inactive limit 17,3
...