Excluding records based on multiple variables - sql

SQL noob here. I'm using MS Access to query a table of streetlight data to exclude lights of a certain size and only where the fixture type is a variant of "Cobra". Is anyone kind enough to give me some guidance on what I might be doing wrong?
I can produce the lights I need to be excluded with:
SELECT *
FROM Lighting
WHERE Lighting.TYPE_FIXTURE LIKE '*cobra*'
AND Lighting.SIZ < '16'
Simple enough. I thought this would be easy to tweak a little bit to get it to exclude these instead of produce them.
SELECT *
FROM Lighting
WHERE Lighting.TYPE_FIXTURE NOT IN ('*Cobra*')
AND Lighting.SIZ NOT IN ('10', '15')
This code excludes the lights I need to be excluded, but also every other type of light that is 100 or 150w. For the life of me, I can't figure out how to exclude ONLY Cobra lights 150w or less.
Through extensive internet research, I tried using an IIF expression to produce a temporary column that would have a value of 0 or 1, depending on if it needed to be excluded or not,
SELECT *
,IIf(Lighting.TYPE_FIXTURE LIKE "*cobra*" AND Lighting.SIZ < 15, 0, 1) AS IncludeFlag
INTO #MyTempTable
FROM Lighting
SELECT *
FROM #MyTempTable
WHERE IncludeFlag = 1
but my only result is an error message that I don't know how to resolve. I've spent all day on this one query and I'm starting to pull my hair out!!

Try this...
SELECT *
FROM Lighting
WHERE (Lighting.TYPE_FIXTURE NOT LIKE '*cobra*'
AND Lighting.SIZ < '16')

Converting from a TRUE and TRUE to a NOT(TRUE and TRUE) involves distributing the NOT inside the brackets and switch the AND to an OR.
The following should give you the results you want:
SELECT *
FROM Lighting
WHERE Lighting.TYPE_FIXTURE Not Like '*cobra*' OR Lighting.SIZ>='16';

Related

How to cast nvarchar to integer?

I have a database I'm running queries on where I cannot change the schema. I am in my second year of database management. We have not touched much on writing actual SQL as opposed to just using the GUI to create our queries and manage our DB's.
I have a population attribute that I need to run SUM on but the population is datatype ncharvar. I need to cast it to int.
I don't know how to do that in SQL though! Can someone please show me? I've been fiddling with it for awhile and I'm out of ideas. I'm very unfamiliar with SQL (as simple as it looks) and this would be helpful.
SELECT dbo_City.CityName, Sum(dbo_City.Population) AS SumOfPopulation
FROM dbo_City
GROUP BY dbo_City.CityName
ORDER BY dbo_City.CityName, Sum(dbo_City.Population);
I need to find what cities have populations between 189,999 and 200,000, which is a very simple query. I'm grouping by city and using the sum of the population. I'm not sure where to insert the 189,999-200,000 figure in the query but I can figure that out later. Right now I'm stuck on casting the ncharvar Population field to an Int so I can run this query!
I found the answer here:
Using SUM on nvarchar field
SELECT SUM(CAST(NVarcharCol as int))
But I'm not sure how to execute this solution. Specifically, I'm not sure where to insert this code in the above provided SQL, and I don't understand why the nvarchar is called nvarcharcol.
From MSDN:
Syntax for CAST:
CAST ( expression AS data_type [ ( length ) ] )
Your solution should look something like this:
SELECT c.CityName, CAST(c.Population AS INT) AS SumOfPopulation
FROM dbo_City AS c
WHERE ISNUMERIC(c.Population) = 1 AND CAST(c.Population AS INT) BETWEEN 189999 AND 200000
ORDER BY c.CityName, CAST(c.Population AS INT)
You shouldn't need the sum function unless you want to know the total population of the table, which would be more useful if it was a table of countries, cities, and city populations, unless this particular city table is broken down further (such as with individual zip codes?). In that case, the below would be the preference:
SELECT c.CityName, SUM(CAST(c.Population AS INT)) AS SumOfPopulation
FROM dbo_City AS c
WHERE ISNUMERIC(c.Population) = 1
GROUP BY c.CityName
HAVING SUM(CAST(c.Population AS INT)) BETWEEN 189999 AND 200000
ORDER BY c.CityName, SUM(CAST(c.Population AS INT))
I hope this helps point you in the right direction.
-C§
Edit: Integrated the "fail safe" from your linked syntax, which should stop that error coming up. It adds a filter to the column to only process those that are able to be cast to a numeric type without extra processing (such as removing the comma as in vkp's response).
I ran into a similar problem where I had temperatures (temp) stored as nvarchar. I wanted to filter out all temperatures under 50F. Unfortunately,
WHERE (temp > '5')
would include temperatures that started with a - sign (-5, -6, ...); even worse, I discovered that temperatures over 100F were also getting discarded.
SOLUTION:
WHERE (CAST (temp as SMALLINT) > '50')
I know this doesn't "directly" answer your question but for the life of me I couldnt find a specific answer to my problem anywhere on the web. I thought it would be lame to answer my own question, so I wanted to add that my discovery to your answer.

EXCEPT returning unpredictable results

I have a table DB_Budget which has 3 columns Business_Unit_Code, Ledger_Period, Budget_GBP. For sake of simplicity, I have left out the other columns.
Data types are -
This table is present in my development and production environment.
While doing some quality checks I ran the below query:
select
Business_Unit_Code,
Ledger_Period,
Budget_GBP
from [SomeLinkedServer].[Database].dbo.DB_BUDGET
where business_unit_code = 'AV' and ledger_period = '200808'
and budget_gbp >= 32269
except
select
Business_Unit_Code,
Ledger_Period,
Budget_GBP
from [Database].dbo.DB_BUDGET
where business_unit_code = 'AV' and ledger_period = '200808'
and budget_gbp >= 32269
I got this -
If I remove the except, this is what I get -
Clearly, data is same in both tables! Why would EXCEPT give me one row?
Things get interesting. I wrap Budget_GBP around LTRIM(RTRIM( ... construct.
And things matched!
I did a bit of googling and found that LTRIM(RTRIM( basically rounds off the float to 32269.2. That might be the reason why they match.
So, to summarize, my first question is why the EXCEPT gives a row in result when the records are matching?
My second question might be simple. As you can see, I am restricted to use the clause budget_gbp >= 32269 in WHERE clause. Reason is when I provide the exact value(which I am copying from SSMS), I get no results. Please let me know what I am doing wrong here.
EDIT - Is there any way the data validation might work? There are 100s of table in the database and it is next to impossible for me to scavenge for float columsn and wrap them around cast. Using EXCEPT is one ways of validating the data in development environment.
Cast the values to fixed point types or strings and re-run your code. The first query would look like:
select Business_Unit_Code, Ledger_Period, cast(Budget_GBP as decimal(18, 2)) as Budget_GBP
With numbers, what you see is not always what you get. So you see 32669.19, but it might really be 32.669.189999.
you could define an accuracy and check if the value is within the specified accuracy of each other.
declare #accuracy float = 0.001
select *
from DB_BUDGET1 t1
full join DB_BUDGET2 t2
on t1.Business_Unit_Code=t2.Business_Unit_Code
and t1.Ledger_Period =t2.Ledger_Period
and t1.Budget_GBP between t2.Budget_GBP-#accuracy and t2.Budget_GBP+#accuracy
where t1.id is null
or t2.id is null
http://www.sqlfiddle.com/#!3/41da0/2/0

INTERSECT not acting as I expect

I'm not sure if this is a symptom of my relative inexperience with SQL, or with h2. I have a view, called VIEW_TRANSACTION_LEGS_DATA, which I need to search in various ways. So, for example, I have:
SELECT HEAD_ID FROM VIEW_TRANSACTION_LEGS_DATA WHERE AMOUNT > 1000
and I also have:
SELECT * FROM
(SELECT HEAD_ID FROM VIEW_TRANSACTION_LEGS_DATA WHERE AMOUNT > 1000)
INTERSECT
(SELECT HEAD_ID FROM VIEW_TRANSACTION_LEGS_DATA WHERE AMOUNT < 2000)
Unfortunately, this isn't working as I expect! There should only be 3 rows returned, whereas I am getting 57 returned.
(Note that the above is a simplified version of what my code actually says; please don't suggest to me to combine the INTERSECTed lines using a BETWEEN since this will not work with the rest of the code.)
I'm sure my problem is a typical SQL newbie type problem, but I simply can't see it! Can some kind person please point me in the right direction?

SQL query exlude data between date and also matching another condition

All,
First time poster on here. I am trying to create a query where I want to exclude data between a date range but also having certain codes.
Date:
(substring(CAST(UTCBigintToUTCTime(starttime) as varchar(19)),0,11) not between '2012-05-08%' and '2012-05-10%
Status Code:
statuscode NOT IN ('58','59'))
What would my statement look like to exclude data that meets BOTH of those conditions? Everything I do excludes all in that date range and all in the status code range.
Thanks in advance. SQL newbie but learning :).
It seems to me that you're over-thinking it a bit, and making it more complex than it needs to be.
And making it this complex, especially with negative logic, will also make it perform poorly.
How about something like:
select * from myTable where starttime < '2012-05-08' and starttime > '2012-05-10' and statuscode < 58 and statuscode > 59
Not sure what database you are using, or exactly what your data types are - adjust slightly as necessary, but try to stay away from nasty date/string conversions and 'NOT' conditions wherever possible.
try this
select * from myTable where convert(date,starttime) not between '2012-05-08' and '2012-05-10' and statuscode not in (58,59)
and let me know.

Convert row data into columns Access 07 without using PIVOT

I am on a work term from school. I am not very comfortable using SQL, I am trying to get a hold of it....
My supervisor gave me a task for a user in which I need to take row data and make columns. We used the Crosstab Wizard and automagically created the SQL to get what we needed.
Basically, we have a table like this:
ReqNumber Year FilledFlag(is a checkbox) FilledBy
1 2012 (notchecked) ITSchoolBoy
1 2012 (checked) GradStudent
1 2012 (notchecked) HighSchooler
2 etc, etc.
What the user would like is to have a listing of all of the req numbers and what is checked
Our automatic pivot code gives us all of the FilledBy options (there are 9 in total) as column headings, and groups it all by reqnumber.
How can you do this without the pivot? I would like to wrap my head around this. Nearest I can find is something like:
SELECT
SUM(IIF(FilledBy = 'ITSchoolboy',1,0) as ITSchoolboy,
SUM(IIF(FilledBy = 'GradStudent',1,0) as GradStudent, etc.
FROM myTable
Could anyone help explain this to me? Point me in the direction of a guide? I've been searching for the better part of a day now, and even though I am a student, I don't think this will be smiled upon for too long. But I would really like to know!
I think your boss' suggestion could work if you GROUP BY ReqNumber.
SELECT
ReqNumber,
SUM(IIF(FilledBy = 'ITSchoolboy',1,0) as ITSchoolboy,
SUM(IIF(FilledBy = 'GradStudent',1,0) as GradStudent,
etc.
FROM myTable
GROUP BY ReqNumber;
A different approach would be to JOIN multiple subqueries. This example pulls in 2 of your categories. If you need to extend it to 9 categories, you would have a whole lot of joining going on.
SELECT
itsb.ReqNumber,
itsb.ITSchoolboy,
grad.GradStudent
FROM
(
SELECT
ReqNumber,
FilledFlag AS ITSchoolboy
FROM myTable
WHERE FilledBy = "ITSchoolboy"
) AS itsb
INNER JOIN
(
SELECT
ReqNumber,
FilledFlag AS GradStudent
FROM myTable
WHERE FilledBy = "GradStudent"
) AS grad
ON itsb.ReqNumber = grad.ReqNumber
Please notice I'm not suggesting you should use this approach. However, since you asked about alternatives to your pivot approach (which works) ... this is one. Stay tuned in case someone else offers a simpler alternative. :-)