How to make Ranking using case by Partition in SQL Server? - sql

I need to do Ranking, if the value is negative, then sort it by Asc, if it is positive then sort it by Desc
select
Itemcode,
isnull(sum(ss.DiscQty * ss.Cost),0) DescCost,
RANK()OVER(Partition by Itemcode order by
case when isnull(sum(ss.DiscQty * ss.Cost),0) < 0 THEN isnull(sum(ss.DiscrepancyQty * ss.Cost),0) END ASC,
case when isnull(sum(ss.DiscQty * ss.Cost),0) > 0 THEN isnull(sum(ss.DiscQty * ss.Cost),0) END DESC
) RANKS
from
ss
Group by
ItemNo

Is this the pattern you are after?
Have simplified the code to highlight what is happening
;WITH Example (n) AS
(
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT -1 UNION ALL
SELECT -2 UNION ALL
SELECT -3
)
SELECT n
,ROW_NUMBER() OVER (ORDER BY ABS(n)-0 DESC)
FROM Example
ORDER BY n,ROW_NUMBER() OVER (ORDER BY ABS(n)-0 DESC)

You cannot change the criteria dynamically. Do the following
SELECT
Brand,
ItemNo,
RANK() OVER (PARTITION BY ItemNo ORDER BY
CASE WHEN ISNULL(Disc, 0) > 0 THEN SUM(Quantity * Item.Cost) ELSE 0 END DESC,
CASE WHEN ISNULL(ST_ItemEntry.Discrepancy, 0) < 0 THEN SUM(Quantity * Item.Cost) ELSE 0 END ASC
) AS [Rank]
FROM
item
GROUP BY
Brand,ItemNo

Related

Division in group by SQL table

I have the following SQL code
SELECT (COUNT(*) filter (WHERE has_a)) AS count_a,
COUNT(*) AS total_count,
process_date
FROM(SELECT process_date::date AS process_date,
(CASE WHEN (columnA > 0) THEN true ELSE false END) AS has_a
FROM my_table)
temptable
GROUP BY process_date
LIMIT 5;
which gives the following table
I want to create a column called percent_a with value (count_a/total_count)*100 grouped by process_date. E.g for row 1 the new column would have value 49.4 i.e. (1030/2085)*100.
I have tried
SELECT process_date,
((COUNT(*) filter (WHERE has_a))/COUNT(*) * 100) AS percent_a,
FROM(SELECT process_date::date AS process_date,
(CASE WHEN (columnA > 0) THEN true ELSE false END) AS has_a,
FROM my_table)
temptable
GROUP BY process_date
ORDER BY process_date DESC
LIMIT 1;
But this just gave 0s.
How can I create the column to display the % I want? I think something is happening with the GROUP BY but I don't know how to fix it.
It's because count returns an integer, you just need to cast it:
SELECT process_date,
(((COUNT(*) filter (WHERE has_balance))::DOUBLE PRECISION)/COUNT(*) * 100) AS percent_a,
FROM(SELECT process_date::date AS process_date,
(CASE WHEN (columnA > 0) THEN true ELSE false END) AS has_a,
FROM my_table)
temptable
GROUP BY process_date
ORDER BY process_date DESC
LIMIT 1;

T SQL Count and Group by calculable column

This code
DECLARE #SNH TABLE
(
cntDATE date,
cntQUEUE varchar(10),
[cntINKTONERBLACK] int
)
INSERT INTO #SNH (cntDATE, cntQUEUE, [cntINKTONERBLACK])
VALUES ('2001-04-04', 'Queue01', 3),
('2001-04-05', 'Queue01', 1),
('2001-04-06', 'Queue01', 100)
SELECT TOP 5
[cntQUEUE] AS cntqueue,
[cntdate],
[cntINKTONERBLACK],
(CASE
WHEN LAG(cntinktonerblack) OVER (PARTITION BY cntqueue ORDER BY cntqueue, cntdate) < cntinktonerblack
THEN 1
ELSE 0
END) AS signalcolumn
FROM
#SNH
WHERE
[cntINKTONERBLACK] IS NOT NULL
ORDER BY
cntqueue, cntDATE ASC
gives the following table
cntqueue
cntdate
cntINKTONERBLACK
signalcolumn
Queue01
2001-04-04
3
0
Queue01
2001-04-05
1
0
Queue01
2001-04-06
100
1
Is there a way to count '1' in signal column and group 1st column to have?
cntqueue
NumberOfJumps
Queue01
1
You can use a subquery:
select cntqueue, sum(signalcolumn)
from (select cntQUEUE,
(case when lag(cntinktonerblack) over (partition by cntqueue order by cntqueue, cntdate) < cntinktonerblack
then 1 else 0
end) as signalcolumn
from [watchdocstatsSU].[dbo].[queuescounters]
where [cntINKTONERBLACK] is NOT null
) q
group by cntqueue
order by cntqueue;

sql purchase items

I need a stored procedure for solve this problem. I have table with name Items With Values
id qty
1 5
2 10
3 15
If a parameter value = 10, and the table will be
id qty
1 0
2 5
3 15
If your dbms supports window functions (ms sql server 2012+ is used below):
declare #prm int = 10;
select id, qty
, case
when qty + tot <= #prm then 0
when tot > #prm then qty
else (qty + tot) - #prm
end currQty
from (
select id, qty, coalesce (sum(qty) over(order by id rows between unbounded preceding and 1 preceding), 0) tot
from
-- your table here
(values
(1,5 )
,(2,10)
,(3,15)
) tbl (id,qty)
) t;
Basically, you want to use a cumulative sum for this purpose. The rest is just arithmetic. I like to phrase this as:
select t.*,
(case when running_qty <= #parameter
then 0
when running_qty - qty <= #parameter
then running_qty - #parameter
else qty
end) as new_qty
from (select t.*,
sum(qty) over (order by id) as running_qty
from t
) t;
Here is a db<>fiddle.

SQL query min and max group by flag

I have a table as below :
How can I craft a SQL select statement so that MIN AND MAX EVENT DATE groups results by FLAG (0,1)?
So the result would be:
Just do conditional aggregation with use of window function
SELECT card_no, descr_reader,
max(CASE WHEN flag = 0 THEN event_date END) date_in,
max(CASE WHEN flag = 1 THEN event_date END) date_out
FROM
(
SELECT *,
COUNT(flag) OVER (PARTITION BY flag ORDER BY id) Seq
FROM table t
)t
GROUP BY card_no, descr_reader, Seq
An alternative if Window function does not work:
SELECT
t1.card_no, t1.descr_reader,
t1.event_date date_in,
(select top 1 event_date from test t2
where t2.card_no = t1.card_no and
t2.reader_no = t1.reader_no and
t2.descr_reader = t1.descr_reader and
t2.event_date > t1.event_date and
t2.flag = 1
order by t2.event_date ) as date_out
FROM test t1
WHERE t1.flag = 0

How to have where clause on row_number within the same select statement?

I'm not able to use where condition on the row number within the same select statement. Results are not consistent if I use a different select statement for applying condition over the rownumber...
SELECT TOP (#lastrow - 1) c.totalRows
,c.ae_effective_enrollment_id
,c.[user_id]
,c.login_name
,c.first_name
,c.last_name
,cm.courseware_title
,cm.courseware_code
,#courseware_id assetId
,c.enrollment_status_id
,CASE
WHEN c.enrollment_status_id = 2
AND c.is_self_enrolled = 0
THEN 'Admin-' + s.description
WHEN c.enrollment_status_id = 2
AND c.is_self_enrolled = 1
THEN 'Self-' + s.description
ELSE s.description
END AS enrollmentStatus
,c.is_group
,CASE
WHEN c.is_self_enrolled = 0
THEN 1
ELSE 0
END is_admin
,CASE
WHEN c.auma_is_assigned = 1
THEN 'Admin-assigned'
WHEN c.auma_is_assigned = 0
THEN 'Self-assigned'
ELSE 'No-My-Plan'
END AS myplanStatus
, master_assignment_id
,ROW_NUMBER() over(partition by cm.courseware_id,c.user_id order by c.is_self_enrolled)as check_row
FROM enrollmentCTE c
INNER JOIN dbo.courseware_master cm ON cm.courseware_id = #courseware_id
LEFT JOIN #statuscodes s ON s.id = c.enrollment_status_id
WHERE check_row=1 and
enrollment_status_id<>4 and
rownumber > #firstrow
AND rownumber < #lastrow
ORDER BY rownumber
check_row here is not recognised. Please help
SQL order of execution.
FROM clause
WHERE clause
GROUP BY clause
HAVING clause
SELECT clause
ORDER BY clause
the check_row alias was made in the select part so it doesn't exist yet in the context
EDIT
done some testing. can't seem to get it right. as a temporary solution you could attempt to put the
ROW_NUMBER() over(...
in the where clause aswell
EDIT:
another option from the MSDN website is
Returning a subset of rows
The following example calculates row numbers for all rows in the SalesOrderHeader table in the order of the OrderDate and returns only rows 50 to 60 inclusive.
USE AdventureWorks2012;
GO
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS RowNumber
FROM Sales.SalesOrderHeader
)
SELECT SalesOrderID, OrderDate, RowNumber
FROM OrderedOrders
WHERE RowNumber BETWEEN 50 AND 60;
SELECT totalRows, ae_effective_enrollment_id, user_id, login_name, first_name, last_name, check_row FROM
(SELECT TOP (#lastrow - 1) c.totalRows as totalRows
,c.ae_effective_enrollment_id as ae_effective_enrollment_id
,c.[user_id] as user_id
,c.login_name as login_name
,c.first_name as first_name
,c.last_name as last_name
,cm.courseware_title as courseware_title
,cm.courseware_code as courseware_code
,#courseware_id as assetId
,c.enrollment_status_id as enrollment_status_id
,CASE
WHEN c.enrollment_status_id = 2
AND c.is_self_enrolled = 0
THEN 'Admin-' + s.description
WHEN c.enrollment_status_id = 2
AND c.is_self_enrolled = 1
THEN 'Self-' + s.description
ELSE s.description
END AS enrollmentStatus
,c.is_group
,CASE
WHEN c.is_self_enrolled = 0
THEN 1
ELSE 0
END is_admin
,CASE
WHEN c.auma_is_assigned = 1
THEN 'Admin-assigned'
WHEN c.auma_is_assigned = 0
THEN 'Self-assigned'
ELSE 'No-My-Plan'
END AS myplanStatus
, master_assignment_id
,ROW_NUMBER() over(partition by cm.courseware_id,c.user_id order by c.is_self_enrolled)as check_row
FROM enrollmentCTE c
INNER JOIN dbo.courseware_master cm ON cm.courseware_id = #courseware_id
LEFT JOIN #statuscodes s ON s.id = c.enrollment_status_id
WHERE enrollment_status_id<>4 and
rownumber > #firstrow
AND rownumber < #lastrow
ORDER BY rownumber ) t where check_row = 1
NOTE - add all column name in first select statement
Use CTE to make your query based on another
;WITH CTE AS(
SELECT c.totalRows
,c.ae_effective_enrollment_id
,c.[user_id]
,c.login_name
,c.first_name
,c.last_name
,cm.courseware_title
,cm.courseware_code
,#courseware_id assetId
,c.enrollment_status_id
,CASE
WHEN c.enrollment_status_id = 2
AND c.is_self_enrolled = 0
THEN 'Admin-' + s.description
WHEN c.enrollment_status_id = 2
AND c.is_self_enrolled = 1
THEN 'Self-' + s.description
ELSE s.description
END AS enrollmentStatus
,c.is_group
,CASE
WHEN c.is_self_enrolled = 0
THEN 1
ELSE 0
END is_admin
,CASE
WHEN c.auma_is_assigned = 1
THEN 'Admin-assigned'
WHEN c.auma_is_assigned = 0
THEN 'Self-assigned'
ELSE 'No-My-Plan'
END AS myplanStatus
, master_assignment_id
,ROW_NUMBER() over(partition by cm.courseware_id,c.user_id order by c.is_self_enrolled) as check_row
FROM enrollmentCTE c
INNER JOIN dbo.courseware_master cm ON cm.courseware_id = #courseware_id
LEFT JOIN #statuscodes s ON s.id = c.enrollment_status_id
WHERE enrollment_status_id<>4
AND rownumber > #firstrow
AND rownumber < #lastrow
)
SELECT TOP (#lastrow - 1) *
FROM CTE
WHERE check_row = 1
ORDER BY rownumber