sql get a number whose range is another number - c#

I have a column of price breaks and need to find the row that contains a certain quantity. It is set up like this:
id | MinimumQuantity | Price
-----------------------------------
1 | 1 | 10
1 | 10 | 20
1 | 25 | 30
...and the quantity could be any number. So, if the quantity is 1 I would need to get the Price 10 (1-10), if the quantity is 15 I would need to get the Price 20 (10-25) and if the quantity is 100 I would need to get Price 30 (25+). So far I have:
select Price from myTable where MinimumQuantity >= #myQuantity and id = #myID
...but of course this doesn't return 25+, it seems like it should be simple but I'm stumped. Thanks for your help.

here is proper query for mysql:
SELECT `Price` from `myTable`
WHERE #myQuantity >= `MinimumQuantity` and `id` = #myID
ORDER BY `MinimumQuantity` ASC
LIMIT 1
for sql server:
SELECT top 1 [Price] from [myTable]
WHERE #myQuantity >= [MinimumQuantity] and [id] = #myID
ORDER BY [MinimumQuantity] ASC

Related

is there a way to use OFFSET and FETCH in MS access or anything similiar in a query, set query has to be used in ASP.NET [duplicate]

Is it possible to emulate the following MySQL query:
SELECT * FROM `tbl` ORDER BY `date` DESC LIMIT X, 10
(X is a parameter)
in MS Access?
While the Access/JET TOP keyword does not directly provide an OFFSET capability, we can use a clever combination of TOP, a subquery, and a "derived table" to obtain the same result.
Here is an example for getting the 10 rows starting from offset 20 in a Person table in ORDER BY Name and Id...
SELECT Person.*
FROM Person
WHERE Person.Id In
(
SELECT TOP 10 A.Id
FROM [
SELECT TOP 30 Person.Name, Person.Id
FROM Person
ORDER BY Person.Name, Person.Id
]. AS A
ORDER BY A.Name DESC, A.Id DESC
)
ORDER BY Person.Name, Person.Id;
Essentially, we query the top 30, reverse the order, query the top 10, and then select the rows from the table that match, sorting in forward order again. This should be fairly efficient, assuming the Id is the PRIMARY KEY, and there is an index on Name. It might be that a specific covering index on Name, Id (rather than one on just Name) would be needed for best performance, but I think that indexes implicitly cover the PRIMARY KEY.
Another way - Let say you want from 1000 to 1999 records in a table called table1 (of course if you have that many records) you can do something like this.
MSSQL
SELECT *
FROM table1 LIMIT 1000, 1999;
MS Access
SELECT TOP 1000 *
FROM table1
Where ID NOT IN (SELECT TOP 999 table1.ID FROM table1);
To break this down
SELECT TOP NumA *
FROM table1
Where ID NOT IN (SELECT TOP NumB table1.ID FROM table1);
UpperLimit = 1999
LowerLimit = 1000
NumA = UpperLimit - LowerLimit + 1
ex. 1000 = 1999 - 1000 + 1
NumB = LowerLimit -1
ex. 999 = 1000 - 1
A better query would be:
SELECT Users.*
FROM Users
WHERE Users.id In
(
SELECT TOP X A.id
FROM [
SELECT TOP Y Users.*
FROM Users
ORDER BY Users.reg_date DESC
]. AS A
ORDER BY A.reg_date ASC
)
ORDER BY Users.reg_date DESC
Where
if((totalrows - offset) < limit) then
X = (totalrows - offset)
else
X = limit
And:
Y = limit + offset
For example, if total_rows = 12, and we set the limit to 10 (show 10 users per page), and the offset is calculated as p * limit - (limit) where p is the number of the current page, hence in the first page (p = 1) we will get: X = 12 and Y = 10, on the second X = 2 and Y = 20. The list of users is ordered by registration date (descending).
Simple and fastest solution.
myTable {ID*, Field2, Filed3...}
Assume your SortOrder contain primary KEY only
SELECT TOP PageItemsCount tb01.*
FROM myTable AS tb01
LEFT JOIN (
SELECT TOP OffsetValue ID FROM myTable ORDER BY ID ASC
) AS tb02
ON tb01.ID = tb02.ID
WHERE ISNULL(tb02.ID)
ORDER BY tb01.ID ASC
SortOrder based on other fields with duplicated values, in this case you must include your primary key in SortOrder as last one.
For exemple, myTable
+-------+--------+--------+
| ID | Field2 | Filed3 |
+-------+--------+--------+
| 1 | a1 | b |
| 2 | a | b2 |
| 3 | a1 | b2 |
| 4 | a1 | b |
+-------+--------+--------+
SELECT TOP 2 * From myTable ORDER BY FIELD2;
+-------+--------+--------+
| ID | Field2 | Filed3 |
+-------+--------+--------+
| 2 | a | b2 |
| 4 | a1 | b |
| 3 | a1 | b2 |
| 1 | a1 | b |
+-------+--------+--------+
SELECT TOP 2 * From myTable ORDER BY FIELD2, FIELD3;
+-------+--------+--------+
| ID | Field2 | Filed3 |
+-------+--------+--------+
| 2 | a | b2 |
| 4 | a1 | b |
| 1 | a1 | b |
+-------+--------+--------+
But if we add ID to sort order [AS LAST IN FIELDS LIST]
SELECT TOP 2 * From myTable ORDER BY FIELD2, ID;
+-------+--------+--------+
| ID | Field2 | Filed3 |
+-------+--------+--------+
| 2 | a | b2 |
| 1 | a1 | b |
+-------+--------+--------+
Final request
SELECT TOP PageItemsCount tb01.*
FROM myTable AS tb01
LEFT JOIN (
SELECT TOP OffsetValue ID FROM myTable ORDER BY Field2 ASC, ID
) AS tb02
ON tb01.ID = tb02.ID
WHERE ISNULL(tb02.ID)
ORDER BY tb01.Field2 ASC, tb01.ID
You can definitely get the the equivalent of "Limit" using the top keyword. See:
Access Database LIMIT keyword
No, JET SQL does not have a direct equivalent. As a workaround, you could add a WHERE clause that selects an ordered/id column between two values.
If possible, you can also use pass-through queries to an existing MySQL/other database.
While TOP in MS-Access can limit records returned, it does not take two parameters as with the MySQL LIMIT keyword (See this question).

C# Nested Loop for inserting multiples into DB

I have an application used for warehousing furniture. If the user enters a line with a qty > 1, I have a simple while loop where the line is broken out to be many unique lines inserted into a SQL db. I.e.
Item chair Qty 3
Becomes
Item |Qty|Unique Key
Chair |1 |1234
Chair |1 |1235
Chair |1 |1236
--
while (Qty >= 1)
{
//Go Get Next Num
// GetNextNum("LN");
int NextNum = GetNextNum("LN"); //Method to get next number from DB table
SqlConnection conn = new SqlConnection();
SqlCommand cmd = new SqlCommand();
string connStr = ConfigurationManager.ConnectionStrings["FurnitureDB"].ConnectionString;
conn.ConnectionString = connStr;
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = conn;
//SQL Parameter List here
cmd.CommandText = "InsertSODtl";
SqlDataReader datareader = cmd.ExecuteReader();
Qty--;
}
My challenge is, there are some items that have a multiplier, where one item will be in 3 pieces. In which case I append a number behind the unique key:
Item Table - Qty 1 - Unique Key
------------------------------------
Table | 1 | 1234
Table | 1 | 12341
Table | 1 | 12342
So I need a nested while loop/for loop or some method to insert the appropriate number of pieces. So a table for example - there could be 2 tables, each with 3 pieces. So I need to
Item Table - Qty 1 - Unique Key
------------------------------------
Table | 1 | 1234
Table | 1 | 12341
Table | 1 | 12342
Table | 1 | 1235
Table | 1 | 12351
Table | 1 | 12352
I'm struggling to come up with the logic to do this correctly.
Thanks for your suggestions.
One option I would look at is doing this all from within the stored procedure to limit the queries you need to execute. This can be really easily achieved using any type of for loop in SQL. Now i have a basic table setup as below.
ItemTable
Item | nvarchar(50)
Qty | int
UniqueKey | int
ItemClassification
Item | nvarchar(50)
NumberOfPieces | int
Then a simple stored procedure such as:
CREATE PROCEDURE [dbo].[InsertSODtl]
#item nvarchar(50),
#uniqueKey int
AS
BEGIN
SET NOCOUNT ON
DECLARE #pieces int = (SELECT TOP 1 NumberOfPieces FROM ItemClassification WHERE Item = #item)
INSERT INTO ItemTable (Item, Quantity, UniqueKey) VALUES (#item, 1, #uniqueKey)
IF #pieces IS NOT NULL AND #pieces > 1
BEGIN
DECLARE #count int = 1;
WHILE #count < #pieces -- < assures we end -1 max piece count
BEGIN
INSERT INTO ItemTable VALUES (#item, 1, CAST(CAST(#uniqueKey as nvarchar(10)) + CAST(#count as nvarchar(5)) as int))
SET #count = #count + 1
END
END
END
Like I said it is pretty basic and probably not exactly how your tables look but the concept is there.
First query the amount of pieces in the ItemClassification table for the Item type (simple string).
Next insert the record into the ItemTable
Finally if #pieces is not null and #pieces > 1 then we run a loop from 1 to #pieces - 1 inserting back into the ItemTable appending the value to the unique key. Now we have to cast the #uniqueKey and #count as string (nvarchar(10)) as we need to concat the values and not add them together.
Again a pretty basic example but limits the required queries.
This also doesnt require a change to your code and can be done in one query.
Example Use:
EXEC InsertSODtl 'Table', 1234
EXEC InsertSODtl 'Table', 1235
EXEC InsertSODtl 'Chair', 1236
Results in:

Why there is no LastOrDefault method in petapoco like FirstOrDefault?

Let's say this is my table TicketUpdate in SQL Server with some data inside:
_______________________________
| Id | TicketId | Description |
-------------------------------
| 1 | 5 | desc1 |
| 2 | 6 | desc2 |
| 3 | 5 | desc3 |
| 4 | 5 | desc4 |
| 5 | 6 | desc5 |
I want to retrieve the last row with TicketId = 5 in using Petapoco.
There are several methods for retrieving single row like FirstOrDefault which looks like:
db.FirstOrDefault<TicketUpdate>("select * from TicketUpdate where TicketId = 5");
But using this statement it returns the first row with value of TicketId = 5 with a description of desc1.
My question is how can I retrieve the LastOrDefault value then? There is no such methods in Petapoco.
Additional info
Temporarily I can retrieve the last row with TicketId = 5 by nesting the query like
select *
from TicketUpdate
where Id = (select MAX(Id) from TicketUpdate where TicketId = 5)
But is there any methods or better approach for finding the last row like we retrieve First row by using FirstOrDefault method, without nesting the query?
As mentioned in the comments, you should be able to sort your data first.
Try something like this:
db.FirstOrDefault<TicketUpdate>("select TOP 1 * from TicketUpdate where TicketId = 5 orderby [Id] desc");
As long as Id is incremented it should return the last item added for TicketId == 5.
Change your query to get the last record where ID is max. Also you need to use Top 1 to get only one record.
select Top 1 * from TicketUpdate where TicketId = 5 order by ID desc

SUM values from a table and subtract it to a SUM of values from another table having the same IDs

I have two tables, inventory_tbl and withdrawal_tbl, both have product_id, quantity and amount. I would like to sum all the quantity of the inventory_tbl and subtract it to the sum of all the quantity in the withdrawal_tbl that have the same product_id for both tables. Meaning;
inventory_tbl
product_id | quantity | amount
1 | 10 | 10000
2 | 20 | 20000
3 | 30 | 30000
withdrawal_tbl
product_id | quantity | amount
1 | 5 | 5000
2 | 10 | 10000
3 | 20 | 20000
Remaining_tbl
product_id | quantity | amount
1 | 5 | 5000
2 | 10 | 10000
3 | 10 | 10000
I have this SQL Statement so far but it's giving me the wrong information
"SELECT inventory_tbl.product_id As 'Product ID', SUM(inventory_tbl.quantity) - SUM(withdrawal_tbl.quantity), SUM(inventory_tbl.total) - SUM(withdrawal_tbl.total)
FROM withdrawal_tbl, inventory_tbl GROUP BY inventory_tbl.product_id"
Thank you!
You are doing Cross Product instead of Inner join that is the problem.
Change your query to something like this
"SELECT inventory_tbl.product_id As 'Product ID', SUM(inventory_tbl.quantity) - SUM(withdrawal_tbl.quantity), SUM(inventory_tbl.total) - SUM(withdrawal_tbl.total)
FROM withdrawal_tbl inner join inventory_tbl on inventory_tbl.product_id = withdrawal_tbl.product_id GROUP BY inventory_tbl.product_id"
use Inner join for the desired output ,try this :
"SELECT inventory_tbl.product_id As 'Product ID', SUM(inventory_tbl.quantity) - SUM(withdrawal_tbl.quantity), SUM(inventory_tbl.total) - SUM(withdrawal_tbl.total)
FROM inventory_tbl INNER JOIN withdrawal_tbl on inventory_tbl.product_id =withdrawal_tbl.product_id group by inventory_tbl.product_id;"

View and Combine 2 rows in 1 from same table

I have a problem to view my data as I want,
IDFlight | Dep1 | Des1| Date | IDFlight2 | Dep2 | Des2 | Date | Price
---------+------+-----+-------+-----------+------+------+--------+--------
2 | AYT | PRN |20.3.15| 3 | PRN | AYT | 27.3.15| 150
2 | AYT | PRN |20.3.15| 4 | PRN | AYT | 30.3.15| 150
1 | AYT | PRN |23.3.15| 4 | PRN | AYT | 30.3.15| 150
1 | AYT | PRN |17.3.15| 3 | PRN | AYT | 27.3.15| 150
So search query was with Dates +- 3 days both for 2 flights.
in my case every flight is registered alone in table Flights, each flight has his flight number and his direction, date and pricing(e.g return and one way).
now the problem here is, when user selects the return option, there will be displayed 2 flights in one row, (flight 1 go to destination, flight 2 return from destination) also there is a differences between dates line in the example in the picture.
what I am trying to achieve is displaying data like in example above , that every "one way " record should match with the " return " record. even if the first data is repeated.
I have done a lot of research but no result,
also I tried to do with a view but no success
I tried union no success.
#prmDepDay int, #prmDesDay int, #prmDateDep datetime, #prmFrom int, #prmTo int,
#prmDateRe datetime, #prmFromRe int, #prmToRe int, #prmTotalRe int
AS
BEGIN
DROP TABLE departureflights
SELECT TOP(100) PERCENT
t_flights.idflight,
t_flights.flightnumber,
t_departureairport.depairportname,
t_destinationairport.desairportname,
t_flights.startdate,
t_flights.totalseats
INTO departureflights
FROM t_flights
INNER JOIN t_departureairport
ON t_flights.iddepartureairport = t_departureairport.iddepartureairport
INNER JOIN t_destinationairport
ON t_flights.iddestinationairport = t_destinationairport.iddestinationairport
INNER JOIN t_flightdirections
ON t_flights.iddirection = t_flightdirections.iddirection
WHERE t_departureairport.iddepartureairport = #prmFrom
AND t_destinationairport.iddestinationairport = #prmTo
AND startdate >= Dateadd(day,-#prmDepDay,#prmDateDep)
AND startdate <= Dateadd(day,#prmDepDay,#prmDateDep)
--and TotalSeats>= #prmTotal
ORDER BY t_flights.startdate
DROP TABLE returnflights
SELECT t_flights.idflight,
t_flights.flightnumber AS ReFlightNumber,
t_departureairport.depairportname AS ReDepAirportName,
t_destinationairport.desairportname AS ReDesAirportName,
t_flights.enddate ,
t_flights.totalseats
INTO returnflights
FROM t_flights
INNER JOIN t_departureairport
ON t_flights.iddepartureairport = t_departureairport.iddepartureairport
INNER JOIN t_destinationairport
ON t_flights.iddestinationairport = t_destinationairport.iddestinationairport
INNER JOIN t_flightdirections
ON t_flights.iddirection = t_flightdirections.iddirection
WHERE t_departureairport.iddepartureairport = #prmFromRe
AND t_destinationairport.iddestinationairport = #prmToRe
AND enddate >= Dateadd(day,-#prmDesDay,#prmDateRe)
AND enddate <= Dateadd(day,#prmDesDay,#prmDateRe)
AND totalseats>= #prmTotalRe
ORDER BY t_flights.enddate
If you join the t_flights table with itself you should get both the outgoing and returning flight info in one row.
SELECT journey_out.idflight IDFlight,
journey_out.iddepartureairport Dep1,
journey_out.iddestinationairport Des1,
journey_out.enddate Date1,
journey_return.idflight IDFlight2,
journey_return.iddepartureairport Dep2,
journey_return.iddestinationairport Dep2,
journey_return.enddate Date2
FROM t_flights journey_out
INNER JOIN t_flights journey_return
ON journey_out.iddestinationairport = journey_return.iddepartureairport
AND journey_out.enddate < journey_return.startdate
ORDER BY journey_out.startdate
The first join condition makes sure that the flight is going home from the correct airport, and the second condition makes sure that the return journey does not start before the arrival.
If you want to see the one way options in the same result set as the return options you can change it to a LEFT JOIN instead of an INNER JOIN.

Categories

Resources