SQL Server : JOIN and WHERE - sql

I'm trying to create a new table based on particular values that match between two tables and that works fine but my issue comes about when I try to filter the newly joined table by dates.
CREATE TABLE JoinedValuesTable
(
[Ref] INT IDENTITY(1,1) PRIMARY KEY,
[Parties] CHAR(50),
[Accounts] CHAR(50),
[Amount] FLOAT
);
The table above is created okay and I join insert values into it by joining two tables like this....
INSERT INTO JoinedValuesTable ([Parties], [Accounts], [Amount])
SELECT
InputPerson.[PARTY], Input_Y.[R_Account_1], InputPerson.[Amount]
FROM
InputPerson
JOIN
Input_Y ON InputPerson.[Action] = Input_Y.[Action]
And this works fine it's when I try to filter by dates that it doesn't seem to work....
INSERT INTO JoinedValuesTable([Parties], [Accounts], [Amount])
SELECT
InputPerson.[PARTY], Input_Y.[R_Account_1], InputPerson.[Amount]
FROM
InputPerson
JOIN
Input_Y ON InputPerson.[Action] = Input_Y.[Action]
WHERE
InputPerson.[Date] BETWEEN '2018-01-01' AND '2018-03-03'
I'm not getting any values into my new table. Anyone got any ideas?

Do not use between for dates. A better method is:
WHERE InputPerson.[Date] >= '2018-01-01' AND
InputPerson.[Date] < '2018-03-04'
I strongly recommend Aaron Bertrand's blog on this topic: What do BETWEEN and the devil have in common?
This assumes that Date is being stored as a date/time column. If it is a string, then you need to convert it to a date using the appropriate conversion function.

A shameless copy/paste from an earlier answer:
BETWEEN CONVERT(datetime,'2018-01-01') AND CONVERT(datetime,'2018-03-03')
The original answer: Datetime BETWEEN statement not working in SQL Server
I suspect that the datetime versus string is the culprit. Resulting in (without the insert into):
SELECT InputPerson.[PARTY], Input_Y.[R_1], Input_Y.[R_Account_1], InputPerson.[Amount]
FROM InputPerson
JOIN Input_Y ON InputPerson.[Action] = Input_Y.[Action]
WHERE InputPerson.[Date] BETWEEN CONVERT(datetime,'2018-01-01') AND CONVERT(datetime,'2018-03-03')
-- Edit (after comments from Olivier) --
Are you sure the select-statement returns results? Perhaps the Inner-Join combined with the Where-clause results in an empty result set.

Related

SQL NOT IN failed

I am working on a query that will check the temp table if there is a record that do not exist on the main table. My query looks like this
SELECT * FROM [Telemarketing].[dbo].[PDCampaignBatch_temp]
WHERE [StartDateTime] NOT IN (SELECT [StartDateTime] FROM [Telemarketing].[dbo].PDCampaignBatch GROUP BY [StartDateTime])
but the problem is it does not display this row
even if that data does not exist in my main table. What seems to be the problem?
NOT IN has strange semantics. If any values in the subquery are NULL, then the query returns no rows at all. For this reason, I strongly recommend using NOT EXISTS instead:
SELECT t.*
FROM [Telemarketing].[dbo].[PDCampaignBatch_temp] t
WHERE NOT EXISTS (SELECT 1
FROM [Telemarketing].[dbo].PDCampaignBatch cb
WHERE t.StartDateTime = cb.StartDateTime
);
If the set is evaluated by the SQL NOT IN condition contains any values that are null, then the outer query here will return an empty set, even if there are many [StartDateTime]s that match [StartDateTime]s in the PDCampaignBatch table.
To avoid such issue,
SELECT *
FROM [Telemarketing].[dbo].[PDCampaignBatch_temp]
WHERE [StartDateTime] NOT IN (
SELECT DISTINCT [StartDateTime]
FROM [Telemarketing].[dbo].PDCampaignBatch
WHERE [StartDateTime] IS NOT NULL
);
Let's say PDCampaignBatch_temp and PDCampaignBatch happen to have the same structure (same columns in the same order) and you're tasked with getting the set of all rows in PDCampaignBatch_temp that aren't in PDCampaignBatch. The most effective way to do that is to make use of the EXCEPT operator, which will deal with NULL in the expected way as well:
SELECT * FROM [Telemarketing].[dbo].[PDCampaignBatch_temp]
EXCEPT
SELECT * FROM [Telemarketing].[dbo].[PDCampaignBatch]
In production code that is not a one-off, don't use SELECT *, write out the column names instead.
Most likely your issue is with the datetime. You may be only displaying a certain degree of percision like the year/month/date. The data may be stored as year/month/date/hour/minute/second/milisecond. If so you have to match down the the most granluar measurement of the data. If one field is a date and the other is a date time they also will likely never match up. Thus you always get no responses.

Query to select data between two times?

I'm working with Microsoft Access and SQL
I'm trying to select records from table between two times: 6:00:00PM and 11:59:00PM.
Right now I have
SELECT RESERVATION.Reservation_ID, SEAT_RESERVED.Reservation_Time
FROM RESERVATION
INNER JOIN SEAT_RESERVED ON RESERVATION.Reservation_ID = SEAT_RESERVED.Reservation_ID
WHERE timestamps SEAT_RESERVED.RESERVATION_TIME between ('6:00:00PM' and '11:59:00PM');
But this isn't working and the error says it's missing an operator. Please help
SELECT RESERVATION.Reservation_ID, SEAT_RESERVED.Reservation_Time
FROM RESERVATION
INNER JOIN SEAT_RESERVED ON RESERVATION.Reservation_ID = SEAT_RESERVED.Reservation_ID
WHERE TimeValue(SEAT_RESERVED.Reservation_Time) >= TimeValue ('6:00:00PM')
AND TimeValue(SEAT_RESERVED.Reservation_Time) <= TimeValue ('11:59:00PM');
or
SELECT RESERVATION.Reservation_ID, SEAT_RESERVED.Reservation_Time
FROM RESERVATION
INNER JOIN SEAT_RESERVED ON RESERVATION.Reservation_ID = SEAT_RESERVED.Reservation_ID
WHERE TimeValue(SEAT_RESERVED.Reservation_Time) BETWEEN TimeValue ('6:00:00PM')
AND TimeValue ('11:59:00PM');
Both these queries return what you need. The problem is that you need the where clause to have the SEAT_RESERVED.Reservation_Time not timestamps. Another thing to point out is to convert the values specified in the query into a time value. Using the TimeValue function will allow you to convert a specific text into a timevalue allowing you to query between specific times including minutes and seconds.
Hope you find this helpful.
It looks like you have two tables and only 2 different columns. It would be a better practice to put it all in one table. However, if you do want to keep your tables, this is what your schema should look like
Make sure your reservation time is of type datetime, time, or timestamps. In your case, it looks like you are using the timestamps selector.
CREATE TABLE reservation(
reservation_id INT PRIMARY KEY AUTO_INCREMENT,
reservation_name VARCHAR(10)
);
CREATE TABLE seat_reserved(
reservation_id INT,
reservation_time TIMESTAMP
);
Make sure, you're inserting the correct data into your tables.
INSERT INTO reservation(reservation_name)
VALUES("George"), ("Roger"), ("John"), ("Lucas");
INSERT INTO seat_reserved(reservation_id, reservation_time)
VALUES(1, "2016-03-08 17:00:00"),
(2, "2016-03-08 18:00:00"),
(3, "2016-03-08 19:30:00"),
(4, "2016-03-08 12:00:00");
Pay attention to the values we're inserting into the reservation_time column.
The timestamps data type returns a date and a time in 24 hour format.
To select the time portion of a timestamps data-type, you can use the TIME function.
http://www.techonthenet.com/access/functions/date/time.php
SELECT RESERVATION.Reservation_ID, SEAT_RESERVED.Reservation_Time
FROM RSERVATION
INNER JOIN SEAT_RESERVED ON RESERVATION.Reservation_ID = SEAT_RESERVED.Reservation_ID
WHERE TimeValue(SEAT_RESERVED.RESERVATION_TIME) BETWEEN #18:00:00# AND #23:59:00#
I also removed the timestamps part in the WHERE clause because that's incorrect syntax.
I created a fiddle for you to play around with
http://sqlfiddle.com/#!9/83bcf5/6/0

SQL Server : join on uniqueidentifier

I have two tables Backup and Requests.
Below is the script for both the tables
Backup
CREATE TABLE UserBackup(
FileName varchar(70) NOT NULL,
)
File name is represented by a guid. Sometimes there is some additional information related to the file. Hence we have entries like guid_ADD entried in table.
Requests
CREATE TABLE Requests(
RequestId UNIQUEIDENTIFIER NOT NULL,
Status int Not null
)
Here are some sample rows :
UserBackup table:
FileName
15b993cc-e8be-405d-bb9f-0c58b66dcdfe
4cffe724-3f68-4710-b785-30afde5d52f8
4cffe724-3f68-4710-b785-30afde5d52f8_Add
7ad22838-ddee-4043-8d1f-6656d2953545
Requests table:
RequestId Status
15b993cc-e8be-405d-bb9f-0c58b66dcdfe 1
4cffe724-3f68-4710-b785-30afde5d52f8 1
7ad22838-ddee-4043-8d1f-6656d2953545 2
What I need is to return all the rows from userbackup table whose name (the guid) is matches RequestId in the Requests table and the status is 1. So here is the query I wrote
Select *
from UserBackup
inner join Requests on UserBackup.FileName = Requests.RequestId
where Requests.Status = 1
And this works fine. It returns me the following result
FileName RequestId Status
15b993cc-e8be-405d-bb9f-0c58b66dcdfe 15b993cc-e8be-405d-bb9f-0c58b66dcdfe 1
4cffe724-3f68-4710-b785-30afde5d52f8 4cffe724-3f68-4710-b785-30afde5d52f8 1
4cffe724-3f68-4710-b785-30afde5d52f8_Add 4cffe724-3f68-4710-b785-30afde5d52f8 1
This is exactly what I want. But what I don't understand is how it is working. If you notice the result is returning 4cffe724-3f68-4710-b785-30afde5d52f8_Add row as well. The inner join is on varchar and uniqueidentifier, and this join instead of working like "Equals to" comparison works like "contains" comparison. I want to know how this works so that I can be sure to use this code without any unexpected scenarios.
The values on both sides of a comparison have to be of the same data type. There's no such thing as, say, comparing a uniqueidentifier and a varchar.
uniqueidentifier has a higher precedence than varchar so the varchars will be converted to uniqueidentifiers before the comparison occurs.
Unfortunately, you get no error or warning if the string contains more characters than are needed:
select CONVERT(uniqueidentifier,'4cffe724-3f68-4710-b785-30afde5d52f8_Add')
Result:
4CFFE724-3F68-4710-B785-30AFDE5D52F8
If you want to force the comparison to occur between strings, you'll have to perform an explicit conversion:
Select *
from UserBackup
inner join Requests
on UserBackup.FileName = CONVERT(varchar(70),Requests.RequestId)
where Requests.Status = 1
When you compare two columns of different data types SQL Server will attempt to do implicit conversion on lower precedence.
The following comes from MSDN docs on uniqueidentifier
The following example demonstrates the truncation of data when the
value is too long for the data type being converted to. Because the
uniqueidentifier type is limited to 36 characters, the characters that
exceed that length are truncated.
DECLARE #ID nvarchar(max) = N'0E984725-C51C-4BF4-9960-E1C80E27ABA0wrong';
SELECT #ID, CONVERT(uniqueidentifier, #ID) AS TruncatedValue;
http://msdn.microsoft.com/en-us/library/ms187942.aspx
Documentation is clear that data is truncated
When ever you are unsure about your join operation you can verify Actual Execution Plan.
Here is test sample that you can run inside SSMS or SQL Sentry Plan Explorer
DECLARE #userbackup TABLE ( _FILENAME VARCHAR(70) )
INSERT INTO #userbackup
VALUES ( '15b993cc-e8be-405d-bb9f-0c58b66dcdfe' ),
( '4cffe724-3f68-4710-b785-30afde5d52f8' ),
( '4cffe724-3f68-4710-b785-30afde5d52f8_Add' )
, ( '7ad22838-ddee-4043-8d1f-6656d2953545' )
DECLARE #Requests TABLE
(
requestID UNIQUEIDENTIFIER
,_Status INT
)
INSERT INTO #Requests
VALUES ( '15b993cc-e8be-405d-bb9f-0c58b66dcdfe', 1 )
, ( '4cffe724-3f68-4710-b785-30afde5d52f8', 1 )
, ( '7ad22838-ddee-4043-8d1f-6656d2953545', 2 )
SELECT *
FROM #userbackup u
JOIN #Requests r
ON u.[_FILENAME] = r.requestID
WHERE r.[_Status] = 1
Instead of regular join operation SQL Server is doing HASH MATCH with EXPR 1006 in SSMS it is hard to see what is doing but if you open XML file you will find this
<ColumnReference Column="Expr1006" />
<ScalarOperator ScalarString="CONVERT_IMPLICIT(uniqueidentifier,#userbackup.[_FILENAME] as [u].[_FILENAME],0)">
When ever in doubt check execution plan and always make sure to match data types when comparing.
This is great blog Data Mismatch on WHERE Clause might Cause Serious Performance Problems from Microsoft engineer on exact problem.
What is happening here is the FileName is being converted from varchar to a UniqueIdentifier, and during that process it ignores anything after the first 36 characters.
You can see it in action here
Select convert(uniqueidentifier, UserBackup.FileName), FileName
from UserBackup
It works, but to reduce confusion for the next person to come along, you might want to store the RequestId associated with the UserBackup as a GUID in the UserBackup table and join on that.
At the very least put a comment in ;)

How to convert varchar column values into int?

I have a column toysid which is of varchar datatype in one table. Also another table having same the column toysid with int datatype (I know I can modify column for first table but I have to follow some procedure to keep it as varchar).
I have written following query to join the table:
select study.toysid
from study
join concepts on study.toysid = concepts.toysid
The query returns error:
Conversion failed wher converting varchar datatype into int
Hence I have tried below query:
select study.toysid
from study
join concepts on convert(int, study.toysid) = concepts.toysid
I got the same error. How to convert it? I have searched in many websites but I'm unable to get solution. Please anyone help on this.
Make sure you dont have anything other than numbers in your toysid column. I suspect there are characters other than numbers in that column. once you are sure, try the below query..
select study.toysid
from study join concepts
on cast(study.toysid as int) = concepts.toysid
or
select study.toysid
from study join concepts
on cast(study.toysid as varchar(100)) = cast(concepts.toysid as varchar(100))
You can omit such records which having non-numeric value and then cast with integer like below:
select Mystudy.toysid
from concepts
join (Select study.toysid From study WHERe ISNUMERIC(study.toysid)= 1) As MyStudy
on convert(int, MyStudy.toysid) = concepts.toysid

Delete with WHERE - date, time and string comparison - very slow

I have a slow performing query and was hoping someone with a bit more knowledge in sql might be able to help me improve the performance:
I have 2 tables a Source and a Common, I load in some data which contains a Date, a Time and String (whch is a server name), plus some..
The Source table can contain 40k+ rows (it has 30 odd columns, a mix of ints, dates, times and some varchars (255)/(Max)
I use the below query to remove any data from Common that is in source:
'Delete from Common where convert(varchar(max),Date,102)+convert(varchar(max),Time,108)+[ServerName] in
(Select convert(varchar(max),[date],102)+convert(varchar(max),time,108)+ServerName from Source where sc_status < 300)'
The Source Fields are in this format:
ServerName varchar(255) I.E SN1234
Date varchar(255) I.E 2012-05-22
Time varchar(255) I.E 08:12:21
The Common Fields are in this format:
ServerName varchar(255) I.E SN1234
Date date I.E 2011-08-10
Time time(7) I.E 14:25:34.0000000
Thanks
Converting both sides to strings, then concatenating them into one big string, then comparing those results is not very efficient. Only do conversions where you have to. Try this example and see how it compares:
DELETE c
FROM dbo.Common AS c
INNER JOIN dbo.Source AS s
ON s.ServerName = c.ServerName
AND CONVERT(DATE, s.[Date]) = c.[Date]
AND CONVERT(TIME(7), s.[Time]) = c.[Time]
WHERE s.sc_status < 300;
All those conversions to VARCHAR(MAX) are unnecessary and probably slowing you down. I would start with something like this instead:
DELETE c
from [Common] c
WHERE EXISTS(
SELECT 1
FROM Source
WHERE CAST([Date] AS DATE)=c.[Date]
AND CAST([Time] AS TIME(7))=c.[Time]
AND [ServerName]=c.[ServerName]
AND sc_status < 300
);
Something like
Delete from Common inner join Source
On Common.ServerName = Source.ServerName
and Common.Date = Convert(Date,Source.Date)
and Common.Time = Convert(Time, Source.Time)
And Source.sc_Status < 300
If it's too slow after that, then you need some indexes, possible on both tables.
Removing the unecessary conversions will help a lot as detailed in Aaron's answer. You might also consider creating an indexed view over the top of the log table, since you probably dont have much flexibility in that schema or insert DML from the log parser.
Simple example:
create table dbo.[Source] (LogId int primary key, servername varchar(255),
[date] varchar(255), [time] varchar(255));
insert into dbo.[Source]
values (1, 'SN1234', '2012-05-22', '08:12:21'),
(2, 'SN5678', '2012-05-23', '09:12:21')
go
create view dbo.vSource with schemabinding
as
select [LogId],
[servername],
[date],
[time],
[actualDateTime] = convert(datetime, [date]+' '+[time], 120)
from dbo.[Source];
go
create unique clustered index UX_Source on vSource(LogId);
create nonclustered index IX_Source on vSource(actualDateTime);
This will give you an indexed datetime column on which to seek and vastly improve your execution plans at the cost of some insert performance.