Select limit result in mysql - mysql

I have table with these data:
Id City Amount
1 London 25000
2 New York 20000
3 London 23000
4 Paris 22000
5 Moscow 18000
6 London 21000
7 New York 19000
8 Moscow 26000
9 London 24000
10 Moscow 16000
11 London 15000
12 Moscow 23000
13 Paris 19000
14 New York 15000
15 London 26000
I must create SQL as what to get the results as this?
Id City Amount
1 London 25000
2 New York 20000
3 London 23000
4 Paris 22000
5 Moscow 18000
7 New York 19000
8 Moscow 26000
13 Paris 19000
That means I just want to get the maximum of one city only to appear 2 times.
I just want to get the first two records or the last two records
Thanks!

If your MySQL version < 8.0, you can simulate RowNumber functionality, using Session variables. To achieve Partition By functionality based on grouping, we will use two session variables, one for the row number and the other for storing the old City to compare it with the current one, and increment it by 1, if belonging to same City group, else reset to 1.
Following code will get your first two records. You can easily change it to get first n records, by changing 2 to n in the query.
SET #row_number = 0;
SET #city_var = '';
SELECT inner_nest.Id,
inner_nest.City,
inner_nest.Amount
FROM (
SELECT
#row_number:=CASE
WHEN #city_var = City THEN #row_number + 1
ELSE 1
END AS num,
Id,
#city_var:=City as City,
Amount
FROM
table_name
ORDER BY
City) AS inner_nest
WHERE inner_nest.num <= 2
ORDER BY inner_nest.Id ASC
**
SQL Fiddle
**

Related

How to filter users that have multiple rows where row1="value1" and row2="condition2", ... in SQL?

A have the following data
id user_id visited_country
1 12 Spain
2 12 France
3 14 England
4 14 France
5 16 Canada
6 14 Spain
7 16 Mexico
I want to select all users who have visited both Spain and France, excluding those who have visited England. How can I do that in MySQL?
One aggregation approach might be:
SELECT user_id
FROM yourTable
GROUP BY user_id
HAVING SUM(visited_country = 'Spain') > 0 AND
SUM(visited_country = 'France') > 0 AND
SUM(visited_country = 'England') = 0;

Using a three column unique combination in SQL only once

So, I'm managing a table where it's stored the scores of a particular competition.
The table looks like this:
ENTRY_ID TEAM_ID DATE PLACE SCORE
1 1 2021-10-12 Ireland 64
2 2 2021-10-12 Ireland 31
3 3 2021-10-12 France 137
4 2 2021-10-12 France 61
5 5 2021-10-12 France 38
6 1 2021-10-12 France 66
7 2 2021-10-12 Italy 17
8 3 2021-10-12 Italy 61
9 1 2021-10-12 Italy 74
The competition is held at three different places at the same time, with technically all teams being able to have teams in all of them.
Each team however can only win one point so, in the example, it's possible to see that Team 1 would win both in Italy and Ireland, but it should be awarded only one point for the highest score, so only Italy. The point in Ireland should go to the second place.
The query I was trying to get the results is:
SELECT `TEAM_ID`, `PLACE`
FROM `COMPETITION`
WHERE `date` = "2021-10-12"
GROUP BY `PLACE`
ORDER BY `SCORE` DESC, `id` ASC
LIMIT 3
So I could retrieve all three winners with no further processing.
The results I'm trying to achieve should repeat neither the TEAM_ID nor PLACE, in this particular example it should output:
3 FRANCE (Since it has the highest score in France at 137)
1 ITALY (For the highest score in Italy at 74)
2 IRELAND (For the second-highest score in Ireland, since Team 1 already won in Italy)
The production model of this table has far more entries so it's unlikely there would be any clashes with too many second-places.
How can I achieve that?

how to get rows between two string values in mysql

My table looks like this:
id city road_id
-------------------------
1 london 3
2 manchester 3
3 newcastle 3
4 glasgow 3
5 london 5
6 newcastle 5
I know values of two cities and road_id and need something like this:
UPDATE table SET anothercolumn=1 WHERE id>=(id for)london AND id<(id for)glasgow AND road_id=3
to affect only these rows:
1 london 3
2 manchester 3
3 newcastle 3
UPDATE your_table
SET anothercolumn = 1
WHERE id >= (select id from your_table where city = 'london')
AND id < (select id from your_table where city = 'glasgow')
AND road_id = 3

MySQL self join to get past averages

I am trying to find an average of past records in the database based on a specific time frame (between 9 and 3 months ago) if there is no value recorded for a recent sale. the reason for this is recent sales on our website sometimes do not immediately collect commissions so i am needing to go back to historic records to find out what a commission rate estimate might be.
Commission rate is calculated as:
total_commission / gross_sales
It is only necessary to find out what an estimate would be if a recent sale has no "total_commission" recorded
here is what i have tried so far but i think this is wrong:
SELECT
cs.*
,SUM(cs2.gross_sales)
,SUM(cs2.total_commission)
FROM
(SELECT
sale_id
, date
, customer_code
, customer_country
, gross_sales
, total_commission
FROM customer_sale cs ) cs
LEFT JOIN customer_sale cs2
ON cs2.customer_code = cs.customer_code
AND cs2.customer_country = cs.customer_country
AND cs2.date > cs.date - interval 9 month
AND cs2.date < cs.date - interval 3 month
GROUP BY cs.sale_id
so that data would be structured as follows:
sale_id date customer_code customer_country gross_sales total_commission
1 2013-12-01 cust1 united states 10000 1500
2 2013-12-01 cust2 france 20000 3000
3 2013-12-01 cust3 united states 15000 2250
4 2013-12-01 cust4 france 14000 2100
5 2013-12-01 cust5 united states 13000 1950
6 2013-12-01 cust6 france 12000 1800
7 2014-04-02 cust1 united states 10000
8 2014-04-02 cust2 france 20000
9 2014-04-02 cust3 united states 15000
10 2014-04-02 cust4 france 14000
11 2014-04-02 cust5 united states 13000
12 2014-04-02 cust6 france 12000
so I would need to output results from the query similar to this: (based on sales between 9 and 3 months ago from the same customer_code in the same customer_country)
sale_id date customer_code customer_country gross_sales total_commission gross_sales_past total_commission_past
1 2013-12-01 cust1 united states 10000 1500
2 2013-12-01 cust2 france 20000 3000
3 2013-12-01 cust3 united states 15000 2250
4 2013-12-01 cust4 france 14000 2100
5 2013-12-01 cust5 united states 13000 1950
6 2013-12-01 cust6 france 12000 1800
7 2014-04-02 cust1 united states 10000 10000 1500
8 2014-04-02 cust2 france 20000 20000 3000
9 2014-04-02 cust3 united states 15000 15000 2250
10 2014-04-02 cust4 france 14000 14000 2100
11 2014-04-02 cust5 united states 13000 13000 1950
12 2014-04-02 cust6 france 12000 12000 1800
Your query looks mostly right, but I think your outer query needs to be GROUP BY cs.sale_id (assuming that sale_id is unique in the customer_sale table, and assuming that the date column is datatype DATE, DATETIME, or TIMESTAMP).
And I think you want to include a join predicate so that you match only match "past" rows to those rows where you don't have a total commission, e.g.
AND cs.total_commission IS NULL
And I don't think you really need an inline view.
Here's what I came up with:
SELECT cs.sale_id
, cs.date
, cs.customer_code
, cs.customer_country
, cs.gross_sales
, cs.total_commission
, SUM(ps.gross_sales) AS gross_sales_past
, SUM(ps.total_commission) AS total_commission_past
FROM customer_sale cs
LEFT
JOIN customer_sale ps
ON ps.customer_code = cs.customer_code
AND ps.customer_country = cs.customer_country
AND ps.date > cs.date - INTERVAL 9 MONTH
AND ps.date < cs.date - INTERVAL 3 MONTH
AND cs.total_commission IS NULL
GROUP
BY cs.sale_id
Appropriate indexes will likely improve performance of the query. Likely, the EXPLAIN output will show "Using temporary; Using filesort", and that can be expensive for large sets.
MySQL will likely be able to make use of a covering index for the JOIN:
... ON customer_sale (customer_code,customer_country,date,gross_sales,total_commission).

Query to find the running sum of a column(qty) based on type(if 'a' add else subtract)

I have table with data as follows:
Store ItemNo Type Billno Qty
London 1 A 1 10
London 1 A 2 5
London 1 S 1 7
London 1 A 3 5
London 1 S 2 7
London 2 A 1 19
London 2 S 2 5
London 2 A 3 11
Paris 1 A 1 15
Paris 1 S 2 8
Paris 1 A 3 9
Paris 2 A 1 10
Paris 2 S 2 5
Now i want to calculate TotalQty, such that totalqty of qty of an itemno under particular store is calculated based on type. i.e. if type is A, qty should be added to total and if it is S , subtracted from total as shown below. In the example below for store london ,itemno 1 row 3 is the last entry,so the totalQty gives the current quantity availble for that item in that particular store.
Store ItemNo Type BillNo Qty TotalQty
London 1 A 1 10 10
London 1 A 2 5 15
London 1 S 1 7 8
London 1 A 3 5 13
London 1 S 2 7 6
London 2 A 1 19 19
London 2 A 2 5 24
London 2 S 3 11 13
Paris 1 A 1 15 15
Paris 1 S 2 8 7
Paris 1 A 3 9 16
Paris 2 A 1 10 10
Paris 2 S 2 5 5
Assuming I understand you right, you need to use the IIf statement:
SELECT Store, ItemNo, SUM(IIF(Type = 'A', Qty, 0 - Qty)) AS TotalQty
FROM MyTable
GROUP BY Store, ItemNo
should produce the following (untested):
Store ItemNo TotalQty
London 1 8
London 2 13
Paris 1 16
Paris 2 5
I think this is it (I was confused but then spotted your data is inconsistent between table and results):
SELECT S1.Store, S1.ItemNo, S1.Type, S1.Billno, S1.Qty,
(
SELECT SUM(SWITCH(
S2.Type = 'A', S2.Qty,
S2.Type = 'S', 0 - S2.Qty,
TRUE, NULL
))
FROM StoreStuff AS S2
WHERE S2.Store = S1.Store
AND S2.ItemNo = S1.ItemNo
AND S2.Billno <= S1.Billno
) AS TotalQty
FROM StoreStuff AS S1
ORDER
BY S1.Store, S1.ItemNo, S1.Billno;