Reordering groups within a categorical variable - variables

I'm struggling to reorder the categories in an income group variable.
It is currently in alphabetical order but I wish to change it to be permanently in order of amount (so moving £100 000 and greater to the bottom)
Income Group | Freq. Percent Cum.
Under £20 000 | 11 9.73 9.73
£100 000 and greater | 7 6.19 15.93
£20 000 to 29 999 | 18 15.93 31.86
£30 000 to 49 999 | 38 33.63 65.49
£50 000 to 74 999 | 27 23.89 89.38
£75 000 to 99 999 | 12 10.62 100.00

Create a new variable and assign each of the categories a number. For example,
gen order = 1 if income=="Under £20 000"
replace order = 2 if income=="£20 000 to 29 999"
...
replace order = 6 if income=="£100 000 and greater"
sort order
drop order
If the income variable is numeric, rather than string, sub in the numeric values above.

Related

SQL Server : how to count a column that if exist duplicate data, it reuse duplicate data first exist count number

Table A
shop
amount
count
sameShopCount
shop5
100
1
1
shop2
99
2
1
shop3
98
3
1
shop4
97
4
1
shop1
96
5
1
shop2
95
6
2
shop4
94
7
2
shop5
93
8
2
shop5
92
9
3
shop1
91
10
2
shop5
90
11
4
shop3
89
12
2
Expected Result (order by amount desc):
shop
amount
expected result
shop5
100
1
shop2
99
2
shop3
98
3
shop4
97
4
shop1
96
5
shop2
95
2
shop4
94
4
shop5
93
1
shop5
92
1
shop1
91
5
shop5
90
1
shop3
89
3
I want to count shop column similar to count column in Table A. But also if shop exist more than 1 time it will reuse the first exist count number.
How can I achieved this with/without a temp table in SQL Server respectively? (SQL Server 2014 - build v12.0.6108.1)
I had tried something like:
ROW_NUMBER() OVER (ORDER BY amount DESC)
DENSE_RANK() OVER (PARTITION BY shop ORDER BY amount DESC)
Try using max and dense_rank window functions as the following:
with max_shop_amount as
(
select *,
max(amount) over (partition by shop) as mx
from table_name
)
select shop, amount,
dense_rank() over (order by mx desc) expected
from max_shop_amount
order by amount desc
See demo

Rolling On-Hand Remainder column?

CONumber, LineNumber, PartNumber, OrderQty, ScheduleDate, OnHandQty columns are a pure SELECT query with no transformations. I am trying to recreate the RollingOnHand column in SQL.
The rules are
If a part only has one row, report the real [OnHandQty]
If a part has multiple rows, the oldest order consumes its [OrderQty] from [OnHandQty]
The next oldest order pulls its [OrderQty] from the remaining [OnHandQty], repeat until final row of the matching part
The last row of a given part will display the remaining [OnHandQty]
Is this possible to accomplish in an SQL query?
CONumber
LineNumber
PartNumber
OrderQty
ScheduleDate
OnHandQty
RollingOnHand
C02959
00002
Part 01
102
2022-04-01
0
0
C04017
00001
Part 02
2007
2022-04-01
5099
5099
C04107
00001
Part 03
1
2022-03-09
0
0
C04106
00001
Part 04
1
2022-03-09
0
0
C04108
00001
Part 05
1
2022-03-09
0
0
C03514
00002
Part 06
250
2022-03-11
310
250
C03514
00003
Part 06
250
2022-03-18
310
60
C03757
00001
Part 06
250
2022-04-06
310
0
C04225
00002
Part 07
40
2022-03-31
53
53
C03965
00002
Part 08
24
2022-04-04
0
0
C04034
00001
Part 09
88
2022-03-18
128
128
C04144
00002
Part 10
22
2022-04-04
0
0
C04141
00001
Part 10
100
2022-04-04
0
0
C03734
00003
Part 11
116
2022-03-29
103
103
C03379
00001
Part 12
128
2022-03-07
19
19
C03344
00003
Part 13
40
2022-03-11
5
5
C04058
00001
Part 14
407
2022-03-25
0
0
C03697
00002
Part 15
436
2022-04-04
235
235
C03689
00002
Part 16
111
2022-03-16
87
87
C03690
00001
Part 16
250
2022-03-23
87
0
C03690
00002
Part 16
250
2022-04-06
87
0
C03240
00004
Part 17
3
2022-03-16
30
3
C03725
00001
Part 17
250
2022-03-16
30
27
C03725
00002
Part 17
250
2022-03-23
30
0
C03726
00001
Part 17
250
2022-04-01
30
0
C03726
00002
Part 17
250
2022-04-06
30
0
C03596
00017
Part 18
56
2022-04-06
344
344
C03927
00001
Part 19
600
2022-04-04
1800
600
C03927
00002
Part 19
1000
2022-04-06
1800
1200
I think this basically does what you need (Fiddle)
WITH T AS
(
SELECT *,
AlreadyConsumed = SUM(OrderQty) OVER (PARTITION BY [PartNumber] ORDER BY ScheduleDate ASC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),
PrevLineNumber = LAG([LineNumber]) OVER (PARTITION BY [PartNumber] ORDER BY ScheduleDate ASC),
NextLineNumber = LEAD([LineNumber]) OVER (PARTITION BY [PartNumber] ORDER BY ScheduleDate ASC)
FROM Demo
)
SELECT CONumber,
LineNumber,
PartNumber,
OrderQty,
ScheduleDate,
OnHandQty,
RollingOnHand = CASE
--If a part only has one row, report the real [OnHandQty]
WHEN PrevLineNumber IS NULL
AND NextLineNumber IS NULL THEN OnHandQty
--Not the last row and won't use all the remainder up
WHEN NextLineNumber IS NOT NULL AND Remainder > OrderQty THEN OrderQty
--otherwise use what's left
ELSE Remainder
END
FROM T
CROSS APPLY (SELECT CASE WHEN AlreadyConsumed > OnHandQty THEN 0 ELSE OnHandQty - ISNULL(AlreadyConsumed,0) END) C(Remainder)
The
SUM ... PARTITION BY [PartNumber] ... ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING computes the cumulative OrderQty for all rows before the current row (not including it)
The LAG/ LEAD results are used as indicators to determine whether we are in the first/last rows of a partition and special logic is needed.
I didn't quite follow the rationale behind the business logic so I may have made some invalid simplifications but it returns the desired results with the sample data and anyway the query should be easy to tweak if needed.

Finding Max Price and displaying multiple columns SQL

I have a table that looks like this:
customer_id item price cost
1 Shoe 120 36
1 Bag 180 50
1 Shirt 30 9
2 Shoe 150 40
3 Shirt 30 9
4 Shoe 120 36
5 Shorts 65 14
I am trying to find the most expensive item each customer bought along with the cost of item and the item name.
I'm able to do the first part:
SELECT customer_id, max(price)
FROM sales
GROUP BY customer_id;
Which gives me:
customer_id price
1 180
2 150
3 30
4 120
5 65
How do I get this output to also show me the item and it's cost in the output? So output should look like this...
customer_id price item cost
1 180 Bag 50
2 150 Shoe 40
3 30 Shirt 9
4 120 Shoe 36
5 65 Shorts 14
I'm assuming its a Select statement within a Select? I would appreciate the help as I'm fairly new to SQL.
One method that usually has good performance is a correlated subquery:
select s.*
from sales s
where s.price = (select max(s2.price)
from sales s2
where s2.customer_id = s.customer_id
);

Query a table so that data in one column could be shown as different fields

I have a table that stores data of customer care . The table/view has the following structure.
userid calls_received calls_answered calls_rejected call_date
-----------------------------------------------------------------------
1030 134 100 34 28-05-2018
1012 140 120 20 28-05-2018
1045 120 80 40 28-05-2018
1030 99 39 50 28-04-2018
1045 50 30 20 28-04-2018
1045 200 100 100 28-05-2017
1030 160 90 70 28-04-2017
1045 50 30 20 28-04-2017
This is the sample data. The data is stored on day basis.
I have to create a report in a report designer software that takes date as an input. When user selects a date for eg. 28/05/2018. This date is send as parameter ${call_date}. i have to query the view in such a way that result should look like as below. If user selects date 28/05/2018 then data of 28/04/2018 and 28/05/2017 should be displayed side by side as like the below column order.
userid | cl_cur | ans_cur | rej_cur |success_percentage |diff_percent|position_last_month| cl_last_mon | ans_las_mon | rej_last_mon |percentage_lm|cl_last_year | ans_last_year | rej_last_year
1030 | 134 | 100 | 34 | 74.6 % | 14% | 2 | 99 | 39 | 50 | 39.3% | 160 | 90 | 70
1045 | 120 | 80 | 40 | 66.6% | 26.7% | 1 | 50 | 30 | 20 | 60% | 50 | 30 | 20
The objective of this query is to show data of selected day, data of same day previous month and same day previous years in columns so that user can have a look and compare. Here the result is ordered by percentage(ans_cur/cl_cur) of selected day in descending order of calculated percentage and show under success_percentage.
The column position_last_month is the position of that particular employee in previous month when it is ordered in descending order of percentage. In this example userid 1030 was in 2nd position last month and userid 1045 in 1 st position last month. Similarly I have to calculate this also for year.
Also there is a field called diff_percent which calculates the difference of percentage between the person who where in same position last month.Same i have to do for last year. How i can achieve this result.Please help.
THIS ANSWERS THE ORIGINAL VERSION OF THE QUESTION.
One method is a join:
select t.user_id,
t.calls_received as cr_cur, t.calls_answered as ca_cur, t.calls_rejected as cr_cur,
tm.calls_received as cr_last_mon, tm.calls_answered as ca_last_mon, tm.calls_rejected as cr_last_mon,
ty.calls_received as cr_last_year, ty.calls_answered as ca_last_year, ty.calls_rejected as cr_last_year
from t left join
t tm
on tm.userid = t.userid and
tm.call_date = dateadd(month, -1, t.call_date) left join
t ty
on ty.userid = t.userid and
tm.call_date = dateadd(year, -1, t.call_date)
where t.call_date = ${call_date};

Combine multiple rows using SUM that share a same column value but has different other column values

I thought this would be a very simple query but for some reason, I can't seem to get the results I'm looking for. I have a table that has this structure. I just want a single entry for each account while summing the charges. I don't really care which date I keep, just one of them.
Account Charges Charges2 Date
1 100 50 1/1/2015
1 50 0 1/2/2015
2 50 0 2/4/2015
2 70 30 2/19/2015
3 100 0 1/12/2014
4 0 20 4/3/2015
4 40 20 4/9/2015
The result I want is:
Account Charges Charges2 Date
1 150 50 1/1/2015
2 120 30 2/4/2015
3 100 0 1/12/2014
4 40 40 4/3/2015
The result I currently get is:
Account Charges Charges2 Date
1 100 50 1/1/2015
2 70 30 2/19/2015
3 100 0 1/12/2014
4 40 40 4/9/2015
I thought this would be very simple and I tried below. But this doesn't sum them up, it just seems to return the rows where Charges2 is NOT 0.
SELECT Account, SUM(Charges) As TotCharges, SUM(Charges2) AS TotCharges2
FROM TABLE
GROUP BY Account
ORDER BY Account
You can apply the min() aggregate function to the date to limit the number of rows returned to one per account:
SELECT
Account,
SUM(Charges) AS TotCharges,
SUM(Charges2) AS TotCharges2,
MIN(Date) AS Date
FROM TABLE
GROUP BY Account
ORDER BY Account
Sample SQL Fiddle