Why Is my code being ignored? - sql

When I execute the only thing that is working is the Zipcodes. It is not giving me a service date greater than 08/01/16 or my Billing Providers. I am not sure why.
SELECT Name, BirthDate, Address1, Address2, City, StateProvince, ZipCode, BillingProviderID, ServiceDate, ChargeCatID
FROM dbo.PbrChargeTransactions
WHERE ChargeCatID = 'EM'
AND ServiceDate >= '08/01/16'
AND BillingProviderID IN ('AAD.FD','DSD.DFD','ASDF.DD')
AND ZipCode Like '68730%'
OR ZipCode Like '68792%'
OR ZipCode Like '68739%'
OR ZipCode Like '68718%'
OR ZipCode Like '57069%'
OR ZipCode Like '57031%'
OR ZipCode Like '57078%'
OR ZipCode Like '57066%'
OR ZipCode Like '57063%'
OR ZipCode Like '57037%'
OR ZipCode Like '57073%'
OR ZipCode Like '57029%'
OR ZipCode Like '57070%'
ORDER BY Name

Operator precedence: "And" binds more tightly than "or". That is, only the first zip-code comparison is evaluated with the rest of your "and" conditions. The rest are 'OR's and if they match, you get the record.
Try this:
SELECT Name, BirthDate, Address1, Address2, City, StateProvince, ZipCode, BillingProviderID, ServiceDate, ChargeCatID
FROM dbo.PbrChargeTransactions
WHERE ChargeCatID = 'EM'
AND ServiceDate >= '08/01/16'
AND BillingProviderID IN ('AAD.FD','DSD.DFD','ASDF.DD')
AND (ZipCode Like '68730%'
OR ZipCode Like '68792%'
OR ZipCode Like '68739%'
OR ZipCode Like '68718%'
OR ZipCode Like '57069%'
OR ZipCode Like '57031%'
OR ZipCode Like '57078%'
OR ZipCode Like '57066%'
OR ZipCode Like '57063%'
OR ZipCode Like '57037%'
OR ZipCode Like '57073%'
OR ZipCode Like '57029%'
OR ZipCode Like '57070%'
)
ORDER BY Name

You can use (...) as n8wrl shows or the following, which I think will be faster.
SELECT Name, BirthDate, Address1, Address2, City, StateProvince, ZipCode, BillingProviderID, ServiceDate, ChargeCatID
FROM dbo.PbrChargeTransactions
WHERE ChargeCatID = 'EM'
AND ServiceDate >= '08/01/16'
AND BillingProviderID IN ('AAD.FD','DSD.DFD','ASDF.DD')
AND LEFT(ZipCode,5) in ('68730','68792','68739','68718','57069','57031', '57078','57066','57063','57037','57073','57029','57070')
ORDER BY Name

The issue might be because you missed some parenthesis. Please be aware of the precedence of operators
If you write
A AND B AND zip1 OR zip2 OR zip3
this is equals to
((A AND B) AND zip1) OR zip2 OR zip3
I think you intended to write
A AND B AND (zip1 OR zip2 OR zip3)
where A, B, zip1,... are boolean conditions like zip LIKE '12345%'

Related

subquery in a subquery

How do I create subquery in another subquery?
This is what I got, obviously it doesn't work:
"Select `region` from `region` where `regioncode` IN
(Select `city` from `city` where `citycode` IN
(Select `citycode` from `postcode` where `postcode` LIKE '%" + txtPostcode.Text + "%'))"
Sorry for my amateur questions by the way.
Tabel structure:
Tabel region:
regioncode region provincecode netnumber
Tabel city:
citycode city from to regioncode
"from" and "to" imply the postcode range of the city.
Tabel postcode:
postcode street from to citycode
Here "from" and "to" implies the range of the adress numbers
Tabel province:
provincecode province
So, I should be able to get the region from where the postal code comes from. The postal code will be entered from a textbox.
I got the street, city and adress number range. But the region doesn't work for me.
Also sorry for my broken English, and my amateur questions :.
You might consider using JOINs instead of multiple subqueries.
SELECT region from region r
JOIN city c ON c.regioncode = r.regioncode
JOIN postcode pc ON pc.citycode = c.citycode
WHERE pc.postcode LIKE '%test%'
This would be the equivalent of what you're currently trying to do with subqueries.
EDIT: I've updated the query above to not go through province since it's not needed if city has a regioncode and you're just trying to get region. You could still use subqueries. You should just be getting regioncode from the city table instead of city:
SELECT region FROM region WHERE regioncode IN
(SELECT regioncode FROM city WHERE citycode IN
(SELECT citycode FROM postcode WHERE postcode LIKE '%test%')
)
I'm just using test as a temp value for whatever would be in txtPostcode.Text

How to run multiple SQL queries whose values change?

Let's say I have a database of Amazon customers who made purchases in the last year. It is pretty detailed and has columns like name, age, zip code, income level, favorite color, food, music, etc. Now, let's say I run a query such that I return all Amazon customers who bought Book X.
SELECT NAME, AGE, ZIPCODE, INCOME, FAVECOLOR, FAVEFOOD, FAVEMUSIC
FROM [Amazon].[dbo].[Customers]
WHERE BOOK = "X"
This query will return a bunch of customers who bought Book X. Now, I want to iterate through each of those results (iterate through each customer) and create a query based on each customer's individual age, zipcode, and income.
So if the first result is Bob, age 32, lives in zipcode 90210, makes $45,000 annually, create a query to find all others like Bob who share the same age, zipcode, and income. If the second result is Mary, age 41, lives in zipcode 10004, makes $55,000 annually, create a query to find all others like Mary who share the same age, zipcode, and income.
How do I iterate through customers who bought Book X and run multiple queries whose values (age, zipcode, income) are changing? In terms of viewing the results, it'd be great if I could see Bob, followed by all customers who are like Bob, then Mary, and all customers who are like Mary.
Is this even possible in SQL? I know how to do this in C# (for/next loops with if/then statements inside) but am new to SQL, and the data is in SQL.
I use SQL Server 2008.
If i understood your requirement correctly then a nested quesry should do the job. SOmething like this:
SELECT distinct NAME, AGE, ZIPCODE, INCOME, FAVECOLOR, FAVEFOOD, FAVEMUSIC
FROM [Amazon].[dbo].[Customers] a, (SELECT NAME, AGE, ZIPCODE, INCOME, FAVECOLOR, FAVEFOOD, FAVEMUSIC
FROM [Amazon].[dbo].[Customers]
WHERE BOOK = "X" and name = 'Bob') b
WHERE BOOK = "X" and a.age=b.age and a.zipcode= b.zipcode and a.income=b.income
EDIT: A generic query will be [This will have list of all users]:
SELECT distinct NAME, AGE, ZIPCODE, INCOME, FAVECOLOR, FAVEFOOD, FAVEMUSIC
FROM [Amazon].[dbo].[Customers] a, (SELECT distinct NAME, AGE, ZIPCODE, INCOME, FAVECOLOR, FAVEFOOD, FAVEMUSIC
FROM [Amazon].[dbo].[Customers]
WHERE BOOK = "X" ) b
WHERE a.BOOK = b.book and a.age=b.age and a.zipcode= b.zipcode and a.income=b.income
order by name
Something like this can do it in one query:
;WITH cteSource as
(
SELECT NAME, AGE, ZIPCODE, INCOME, FAVECOLOR, FAVEFOOD, FAVEMUSIC
FROM [Amazon].[dbo].[Customers]
WHERE BOOK = "X"
)
SELECT sr.NAME AS SrcName, cu.NAME AS LikeName
FROM [Amazon].[dbo].[Customers] AS cu
JOIN cteSource As sr
ON cu.AGE = sr.AGE
And cu.ZIPCODE = sr.ZIPCODE
And cu.INCOME = sr.INCOME
Something like this will let you chase related customers to an arbitrary, e.g. 5 here, degree of separation. By constructing the JOINs correctly you can do things like match income within a range, ... .
with Book as (
select Id, Name, Age, ZIPCode, Income -- ...
from Amazon.dbo.Customers
where Book = 'X' ),
RelatedCustomers as (
select C.Id, C.Name, C.Age, C.ZIPCode, C.Income, 1 as Depth -- ...
from Amazon.dbo.Customers as C inner join
Book as B on B.Id <> C.Id and Abs( B.Income - C.Income ) < 2000 -- and ...
union all
select C.Id, C.Name, C.Age, C.ZIPCode, C.Income, RC.Depth + 1-- ...
from Amazon.dbo.Customers as C inner join
RelatedCustomers as RC on RC.Id <> C.Id and Abs( RC.Income - C.Income ) < 2000 -- and ...
where Depth < 5 )
select *
from RelatedCustomers
I think you need two separate queries. First one to bring back the customers, once a customer such as Bob is selected a second query is performed based on Bob's attributes.
A simple example would be a forms application that has two grids. The first displays a list of the users. When you select one of the users the second grid is populated with the results of the second query.
The second query would be something like:
SELECT NAME, AGE, ZIPCODE, INCOME, FAVECOLOR, FAVEFOOD, FAVEMUSIC
FROM [Amazon].[dbo].[Customers]
WHERE Age = #BobsAge AND ZipCode = #BobsZipCode AND Income = #BobsIncome
It sounds like you want a simple self-join:
SELECT
MatchingCustomers.NAME,
MatchingCustomers.AGE,
MatchingCustomers.ZIPCODE,
MatchingCustomers.INCOME,
MatchingCustomers.FAVECOLOR,
MatchingCustomers.FAVEFOOD,
MatchingCustomers.FAVEMUSIC
FROM
[Amazon].[dbo].[Customers] SourceCustomer
LEFT JOIN [Amazon].[dbo].[Customers] MatchingCustomers
ON SourceCustomer.Age = MatchingCustomer.Age
AND SourceCustomer.ZipCode = MatchingCustomer.ZipCode
AND SourceCustomer.Income = MatchingCustomer.Income
WHERE
SourceCustomer.Book = 'X'
If you want to see the all source customers and all of their matches in a single result set you can remove the where clause and select data SourceCustomer also:
SELECT
SourceCustomer.Name SourceName,
SourceCustomer.Age SourceAge
SourceCustomer.ZipCode SourceZipCode,
SourceCustomer.Income SourceIncome,
MatchingCustomers.NAME,
MatchingCustomers.AGE,
MatchingCustomers.ZIPCODE,
MatchingCustomers.INCOME,
MatchingCustomers.FAVECOLOR,
MatchingCustomers.FAVEFOOD,
MatchingCustomers.FAVEMUSIC
FROM
[Amazon].[dbo].[Customers] SourceCustomer
LEFT JOIN [Amazon].[dbo].[Customers] MatchingCustomers
ON SourceCustomer.Age = MatchingCustomer.Age
AND SourceCustomer.ZipCode = MatchingCustomer.ZipCode
AND SourceCustomer.Income = MatchingCustomer.Income
WHERE
SourceCustomer.Book = 'X'

DB2 SQL Join and Max value

The database I'm accessing has two tables I need to query using DB2 SQL, shown here as nametable and addresstable. The query is for finding all of the people with a certain balance due. The addresses are stored in a separate table to keep track of address changes. In addresstable, the latest address is determined by a sequence number (ADDRSEQUENCE). The AddressID field is present in both tables, and is what ties each person to specific addresses. The highest sequence number is the current address. I need that current address for each person and only that one. I know I'm going to have to use MAX somewhere for the sequence number, but I can't figure out how to position it given the join. Here's my current query, which of course returns all addresses...
SELECT NAMETABLE.ACCTNUM AS ACCOUNTNUMBER,
NAMETABLE.NMELASTBUS AS LASTNAME,
NAMETABLE.NAME_FIRST AS FIRSTNAME,
NAMETABLE.BALDUE AS BALANCEDUE,
ADDRESSTABLE.STREETNAME AS ADDR,
ADDRESSTABLE.ADDRLINE2 AS
ADDRLINE2,ADDRESSTABLE.CITYPARISH AS CITY,
ADDRESSTABLE.ADDRSTATE AS STATE,
ADDRESSTABLE.ZIPCODE AS ZIP,
ADDRESSTABLE.ADDIDSEQNO AS ADDRSEQUENCE
FROM NAMETABLE JOIN ADDRESSTABLE ON NAMETABLE.ADDRESSID = ADDRESSTABLE.ADDRESSID
WHERE NAMETABLE.BALANCEDUE >= '50.00'
You can do a sub-select on the MAX(ADDRSEQUENCE) like so:
SELECT
N.ACCTNUM AS ACCOUNTNUMBER
,N.NMELASTBUS AS LASTNAME
,N.NAME_FIRST AS FIRSTNAME
,N.BALDUE AS BALANCEDUE
,A.STREETNAME AS ADDR,
,A.ADDRLINE2 AS
,A.ADDRLINE2
,A.CITYPARISH AS CITY,
,A.ADDRSTATE AS STATE,
,A.ZIPCODE AS ZIP,
FROM NAMETABLE AS N
JOIN ADDRESSTABLE AS A
ON N.ADDRESSID = A.ADDRESSID
WHERE N.BALANCEDUE >= '50.00'
AND A.ADDRSEQUENCE = (
SELECT MAX(ADDRSEQUENCE)
FROM ADDRESSTABLE AS A2
WHERE A.ADDRESSID = A2.ADDRESSID
)
This is pretty quick in DB2.
You can use a row_number and partition by to do this. Something like this:
with orderedaddress as (
select row_number() over (partition by ADDRESSID order by ADDRSEQUENCE desc) as rown,
STREETNAME,ADDRESSID, ... from ADDRESSTABLE
)
select NAMETABLE.ACCTNUM AS ACCOUNTNUMBER,
...
oa.STREETNAME
...
from NAMETABLE JOIN orderedaddress oa on NAMETABLE.ADDRESSID = oa.ADDRESSID
where oa.rown = 1
and NAMETABLE.BALANCEDUE >= '50.00'

Query for Counting number of orders by UK postcode

I have got a table of orders placed by customer , what i want is to check from which part of the country orders are coming historically, I can only check this by postcodes , for intance an order with post code SK... means its stockport , similarly the post code starting from M .. means the order is from manchester, Is it possible to write a query which can count the orders by postcode.
Some of the fields of the Order table:
OrderNumber OGUID custID firstname last name address postcode email authorisation date etc...
Any suggestion or assistance will be appreciated.
Thanks
Here is way that works... but it can get too long for a huge list. I will try to find a way around that problem.
SELECT
CASE
WHEN postcode LIKE 'SK%' THEN 'SK'
WHEN postcode LIKE 'M%' THEN 'M'
END AS group_by_value
, COUNT(*) AS group_by_count
FROM [Table] a
GROUP BY
CASE
WHEN postcode LIKE 'SK%' THEN 'SK'
WHEN postcode LIKE 'M%' THEN 'M'
END
If you have a table that contains the city code and city name, then you might be able to use something like the following which joins your orders table to the codes using a LIKE:
select o.postcode,
c.city,
count(c.code) over(partition by c.code) Total
from orders o
inner join codes c
on o.postcode like '%'+c.code+'%'
See SQL Fiddle with Demo
You can use GROUP BY to get the total number of orders in each postcode:
select postcode, count(postcode) TotalOrdersByPostCode
from orders
group by postcode
If you want the City included, then you can also GROUP BY city:
select city, postcode, count(postcode) TotalOrdersByPostCode
from orders
group by city, postcode
select count(1) over(partition by postcode) as countByPostcode, othecolumnhere
from Order
Have you tried something like this? The town part of the postcode will be the first 1 or 2 bytes, delimited by a number after, I think. So this will give you the first few letters.
select substring(postcode,1, patindex('%[0-9]%',postcode)-1), count(*)
from Order
group by substring(postcode,1, patindex('%[0-9]%',postcode)-1)
Then you'll have to decode M into Manchester, W into West London, GU into Guildford etc...

How to query several database fields based on a a single case structure

In my Oracle database, I have a table called Customers. There are fields for name, zip, city etc., but there are also fields for invoicename, invoicezip and invoicecity. For some records the invoicespecific fields are not set, and in that case the invoice method should use the information from name, zip and city.
I use the following query now:
select
case when c.InvoiceName is null then c.Name else c.InvoiceName end as Name,
case when c.InvoiceName is null then c.Zip else c.InvoiceZip end as Zip,
case when c.InvoiceName is null then c.City else c.InvoiceCity end as City
<...>
from
Customers c
where
Accountnumber=:accountnumber
Note that the check is on InvoiceName only. If that value is set I want to return all the invoice-specific fields, if not I want to return all the "non-invoice-specific" fields.
What I would like to do is something like this
select
case when c.InvoiceName is not null
then
c.InvoiceName as Name,
c.InvoiceZip as Zip,
c.InvoiceCity as City
<...>
else
c.Name,
c.Zip,
c.City
<...>
end
from
customers c
Is there way to do this or something like it?
A CASE expression can only return one value, not 3, so you do need the 3 CASE expressions. Using DECODE would be slightly more concise, but DECODE is Oracle-specific whereas CASE is ANSI standard and so preferable. But for info it would look like:
select
decode(c.InvoiceName,null,c.Name,c.InvoiceName) as Name,
decode(c.InvoiceName,null,c.Zip,c.InvoiceZip) as Zip,
decode(c.InvoiceName,null,c.City,c.InvoiceCity) as City
<...>
from
Customers c
where
Accountnumber=:accountnumber
Another rarely-used but very applicable Oracle-specific function is NVL2:
select
nvl2(c.InvoiceName,c.InvoiceName,c.Name) as Name,
nvl2(c.InvoiceName,c.InvoiceZip,c.Zip) as Zip,
nvl2(c.InvoiceName,c.InvoiceCity,c.City) as City
<...>
from
Customers c
where
Accountnumber=:accountnumber
I think you need the COALESCE function to clean up your select statement. It will take the first non null value in the list.
select
coalesce(c.InvoiceName, c.Name) Name,
coalesce(c.InvoiceZip, c.Zip) Zip,
coalesce(c.InvoiceCity, c.City) City
EDIT: By shahkalpesh
I am assuming that fields with Invoice in it will be NULL, when InvoiceName is NULL.
select
coalesce(c.InvoiceName, c.Name) Name,
coalesce(c.InvoiceName, c.Zip, c.InvoiceZip) Zip,
coalesce(c.InvoiceName, c.City, c.InvoiceCity) City