Avoid repeated values on SQL query, reservations application - c#

first time I ask a question here, I'm coding a reservations application on C# using Visual Studio 2015, but I have a problem trying to show free rooms on a data grid view, here is the query i'm using:
SELECT clientID, cost, arrival, roomNumber, resvNum, departure, size
FROM roomswithresvView
WHERE (roomNumber NOT IN
(SELECT roomNumber
FROM roomswithresvView AS roomswithresvView_1
WHERE (arrival BETWEEN #date1 AND #date2)
OR (departure BETWEEN #date1 AND #date2)))
The problem is that if a room has more than one reservation, the query will show it multiple times, I have tried using DISTINCT but I can only make work with one column and I haven't been able to make GROUP BY work.
Thanks for your attention.
Query Sample
For example, if I test the query with 2016-07-06 as date1 and 2016-07-07 as date2, it will repeat room 1005 because it has two reservations on the database.

Where were you putting the DISTINCT?
You need a table for rooms, and a table for reservations. Then you need a subquery to find reservations that clash with your requested dates. This is where you use DISTINCT. Then you need an outer query to find all rooms not returned in the subquery. Don't forget the case where you have an existing reservation that starts before and ends after your requested dates! Putting that all together, you get this...
insert into room(costPerNight, roomNumber, size)
values
(55, 1, 13),
(65, 2, 15),
(85, 3, 20)
;
create table reservation(
id int identity (1,1) not null,
roomId int not null,
dateIn date not null,
dateOut date not null
)
insert into reservation (roomId, dateIn, dateOut)
values
(1,'2016-07-01','2016-07-03'),
(1,'2016-07-05','2016-07-08'),
(2,'2016-07-01','2016-07-08')
*/
declare #requestedDateIn date = '2016-07-03'
declare #requestedDateOut date = '2016-07-05';
select * from room where id not in(
--find clashing reservations
select distinct roomId from reservation where
(dateOut > #requestedDateIn and dateOut < #requestedDateOut)
or (dateIn > #requestedDateIn and dateIn < #requestedDateOut)
or (dateIn < #requestedDateIn and dateOut > #requestedDateOut)
)

Related

Select Count days between two dates using LINQ

I need to get the number of holidays between two dates. I have tried using the query below but I'm getting an incorrect count number.
StartDate
EndDate
01/2/2022
03/2/2022
17/2/2022
19/2/2022
SELECT COUNT(*) FROM table
WHERE StartDate <= '02/2/2022' and EndDate >= '19/2/2022'
how I make this date => '02/2/2022' return count of day that between two dates from the first row from the table and get count day from the second row.
The count must be 5 days.
The simplest way of doing it is to have a table that has one row per day for every day from eg year 2000 to year 2099, then you can:
SELECT COUNT(*)
FROM
cal --your dates table
INNER JOIN h. --your holiday table
ON cal.d BETWEEEN h.start AND h.end
WHERE
cal.d BETWEEN '2022-02-02' AND '2022-02-19'
The join will produce 6 rows, the where trims it to 5, there is your count
Generating the calendar table, or its equivalent (an arbitrary series of dates) is an exercise for the reader.. See something like this

Can we insert some data along with insert value select query in c# winform

I want to insert the date and month (which is in two datetimepicker) along with insert value select query.
I have five columns in my invoice table
Student_id, Amount, Fee_description, issue_date, month
I can insert the values for the first three columns but the remaining two are null for which I don't know where to put the datetimepicker value??
I take a datatimepicker for date and month in the design view of the form
insert into invoice (Student_id, Amount, Fee_description, issue_date, month)
select
student.Student_id,
Fee.Fee_Amount, Fee.fee_type
from
student
join
parent on student.father_nic = parent.father_nic
join
allocate_class on student.Student_id = allocate_class.Student_id
join
class on class.class_id = allocate_class.class_id
join
session on allocate_class.session_id = session.session_id
join
Fee on class.class_id = Fee.class_id
where
session.session_id = 1
and Fee.fee_type = 'Tution Fee'
and student.status = 'active'
Where to add that two that datetimpicker value in the above query?
Sure. It would look something like this:
var cmd = new SqlCommand("insert into invoice (
Student_id,
Amount,
Fee_description,
issue_date,
month
)
select student.Student_id
, Fee.Fee_Amount
, Fee.fee_type
, #issDat
, #mon
from ...", "conn str here");
cmd.Parameters.AddWithValue("#issDat", issueDateDateTimePicker.Value);
cmd.Parameters.AddWithValue("#mon", monthDateTimePicker.Value);
I've used AddWithValue to quickly explain the concept- google for a blog called "can we stop using AddWithValue already" for a long discussion on how to move away from it(it's reasonable in this context as it's not being used for filtering) but for now the concept I'm trying to relate is:
An sql statement can take a fixed value from you:
SELECT 'hello' FROM table
It can also take a fixed parameter you supply:
SELECT #pHello FROM table
Hence adding parameters and filing them with fixed values from your day time pickers (or datetime.Now or whatever) is fine, and what you should be doing to insert fixed values using an INSERT ... SELECT style statement
Side note, it isn't clear if month and issue date are related but if they're the same date then you don't need to store it twice- you can extract the month from a date at any point.

How do I update a value in a table based on some date interval?

So I have a Product table with a price.
I just want to update that price in a date interval.
Example:
apple is 10
And from 2018-02-02 to 2018-03-02 I want to update the price to 12.
I mention that I create a second table PriceInterval to insert the date interval.
enter code herePseudocode for my sqlscript
Hopefully I have understood the question correctly. A possible solution to what you're describing will mean changing the schema slightly. Having a new field in the product intervals for a new price between two dates allows you still keep the default price, when the interval is over. And using a query to select the price based on the date.
DROP TABLE IF EXISTS product_intervals;
DROP TABLE IF EXISTS products;
CREATE TABLE products (
ID INT NOT NULL AUTO_INCREMENT,
`Name` VARCHAR(50) NOT NULL,
Price DECIMAL(18,1) NOT NULL,
CONSTRAINT pkProductId PRIMARY KEY (ID)
);
CREATE TABLE product_intervals (
ID INT NOT NULL AUTO_INCREMENT,
ProductId INT NOT NULL,
DateTo DATETIME NOT NULL,
DateFrom DATETIME NOT NULL,
NewPrice DECIMAL(18,1) NOT NULL,
CONSTRAINT pkProductIntervalId PRIMARY KEY (ID),
CONSTRAINT fkProductId FOREIGN KEY (ProductId) REFERENCES `products`(`ID`) ON DELETE CASCADE
);
INSERT INTO products (`Name`, Price)
SELECT 'Apple', 0.10
UNION ALL SELECT 'Banana', 0.20;
INSERT INTO product_intervals (ProductId, DateTo, DateFrom, NewPrice)
SELECT 2, STR_TO_DATE('2018-02-10T00:00:00','%Y-%m-%dT%H:%i:%s'), STR_TO_DATE('2018-02-15T00:00:00','%Y-%m-%dT%H:%i:%s'), 0.30;
select p.`Name`, CASE WHEN pi.NewPrice IS NOT NULL THEN pi.NewPrice ELSE p.Price END AS Price
FROM products p
left join product_intervals pi ON p.ID = pi.ProductId AND DateFrom > NOW() AND DateTo < NOW();
The key part to this is the left join and the CASE statement in the select query. This code hasnt been fully tested, so it might need a bit of tweaking but hopefully will give you a good indication of what a solution could be.

Strange order of line insertion

I have a stored procedure that inserts a line in a table. This table has an auto incremented int primary key and a datetime2 column named CreationDate. I am calling it in a for loop via my C# code, and the loop is inside a transaction scope.
I run the program twice, first time with a for loop that turned 6 times and second time with a for loop that turned 2 times. When I executed this select on sql server I got a strange result
SELECT TOP 8
RequestId, CreationDate
FROM
PickupRequest
ORDER BY
CreationDate DESC
What I didn't get is the order of insertion: for example the line with Id=58001 has to be inserted after that with Id=58002 but this is not the case. Is that because I put my loop in a transaction scoope? or the precision in the datetime2 is not enough?
It is a question of speed and statement scope as well...
Try this:
--This will create a #numbers table with 1 mio numbers:
DECLARE #numbers TABLE(Nbr BIGINT);
WITH N(N) AS
(SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1)
,MoreN(N) AS
(SELECT 1 FROM N AS N1 CROSS JOIN N AS N2 CROSS JOIN N AS N3 CROSS JOIN N AS N4 CROSS JOIN N AS N5 CROSS JOIN N AS N6)
INSERT INTO #numbers(Nbr)
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM MoreN;
--This is a dummy table for inserts:
CREATE TABLE Dummy(ID INT IDENTITY,CreationDate DATETIME);
--Play around with the value for #Count. You can insert 1 mio rows in one go. Although this runs a while, all will have the same datetime value:
--Use a small number here and below, still the same time value
--Use a big count here and a small below will show a slightly later value for the second insert
DECLARE #Count INT = 1000;
INSERT INTO Dummy (CreationDate)
SELECT GETDATE()
FROM (SELECT TOP(#Count) 1 FROM #numbers) AS X(Y);
--A second insert
SET #Count = 10;
INSERT INTO Dummy (CreationDate)
SELECT GETDATE()
FROM (SELECT TOP(#Count) 1 FROM #numbers) AS X(Y);
SELECT * FROM Dummy;
--Clean up
GO
DROP TABLE Dummy;
You did your insertions pretty fast so the actual CreationDate values inserted in one program run had the same values. In case you're using datetime type, all the insertions may well occur in one millisecond. So ORDER BY CreationDate DESC by itself does not guarantee the select order to be that of insertion.
To get the desired order you need to sort by the RequestId as well:
SELECT TOP 8 RequestId, CreationDate
FROM PickupRequest
ORDER BY CreationDate DESC, RequestId DESC

What is a good algorithm to manipulate a lot of DateTime Records?

I have a SQL server table in form of
DATA,Startdatetime,Enddatetime
And it means that my sensor has an state of DATA in duration of Startdatetime and Enddatetime. I have lots of these data. So is there any algorithm or class or a way to query (in c# level or SQL level) that I can ask in a specific time what was my sensor state?
In SQL if you want the data for instance for '2015-08-16 17:33:45'
select data
from your_table
where '2015-08-16 17:33:45' between Startdatetime and Enddatetime
Expanding the other answer here with your additional requirement of being able to do this over multiple points in time:
DECLARE #startDate DATETIME2(0) = '2015-01-01',
#endDate DATETIME2(0) = '2016-01-01',
#intervals INT;
SELECT #intervals = 2 * DATEDIFF(MINUTE, #startDate, #endDate) + 1;
WITH pointsInTime AS (
SELECT DATEADD(SECOND, 30*(n-1), #startDate) AS p
FROM dbo.[Numbers] AS [n]
WHERE n < #intervals
)
SELECT p.p, t.DATA
FROM [pointsInTime] AS p
LEFT JOIN dbo.yourTable AS t
ON p.p >= StartDateTime AND p.p <= EndDateTime;
Where dbo.Numbers is a bog standard tally table. The idea here is to generate the 30 second intervals using the tally table and then use that to drive the select of your data. Note - I used a left join because I don't know if there's a guarantee of there being data for a given data point. If you don't need such times to show up in your result set, you can safely change it to an inner join.

Categories

Resources