Executing a CASE statement with multiple conditions - sql

Query takes two tables does a left join, then filters out based off preferences. It runs well, however, when I add the 'case' statement I run into issues. The idea was to grab the first digits I need to classify them into a broader category. I need to be able to change the names of a field into something friendly. Any suggestions?
Values for the tr.TENANT_NAICS field follow a format similar to this:
543330- Other Computer Related | 2782 Science
548972- Socials
Would like to change to just:
Other Computer Related
Other Computer Related
Query
select
tr.OCCUPANCY_DATE, tr.END_DATE, tr.TENANT_NAICS,
pr.PROPERTY_STATUS, pr.NRA_BUILDING, pr.MARKET, pr.SUBMARKET, pr.FULL_ADDRESS_ONE_LINE,
pr.LEGAL_OWNER, pr.TRUE_OWNER,
lr.LESSOR_SUBLESSOR,
/* trying to fix here */
(case
when left(tr.TENANT_NAICS, 2)::numeric = 11 THEN 'Other Computer Related'
when left(tr.TENANT_NAICS, 2)::numeric = 21 THEN 'Mining'
when left(tr.TENANT_NAICS, 4)::numeric = 4821 THEN 'Construction'
else tr.TENANT_NAICS
end) as "Tenant Industry"
from space.tran tr
left join property pr on tr.ID = pr.ID
left join lease lr on tr.OID = lr.OID
where
tr.STATUS = 'Existing' and tr.MARKET = 'Seattle'
;
Edit: the exact error I receive is 'Numeric value 'Bu' is not recognized'.

Apparently TENANT_NAICS is a varchar column and there must be at least one value that starts with BU instead of digits. Try this SQL:
select
tr.OCCUPANCY_DATE, tr.END_DATE, tr.TENANT_NAICS,
pr.PROPERTY_STATUS, pr.NRA_BUILDING, pr.MARKET, pr.SUBMARKET, pr.FULL_ADDRESS_ONE_LINE,
pr.LEGAL_OWNER, pr.TRUE_OWNER,
lr.LESSOR_SUBLESSOR,
/* trying to fix here */
(case
when left(tr.TENANT_NAICS, 2) = '11' THEN 'Other Computer Related'
when left(tr.TENANT_NAICS, 2) = '21' THEN 'Mining'
when left(tr.TENANT_NAICS, 4) = '4821' THEN 'Construction'
else tr.TENANT_NAICS
end) as "Tenant Industry"
from space.tran tr
left join property pr on tr.ID = pr.ID
left join lease lr on tr.OID = lr.OID
where
tr.STATUS = 'Existing' and tr.MARKET = 'Seattle'
;

Related

Sorry I need to hide

Elon Reeve Musk FRS is an entrepreneur and business magnate. He is the founder, CEO, and Chief Engineer at SpaceX; early-stage investor, CEO, and Product Architect of Tesla, Inc.; founder of The Boring Company; and co-founder of Neuralink and OpenAI.
Your inner select returns a table. That can't be used as parameter to match a WHERE IN condition. Instead try using an INNER JOIN
sum(decode(
select sum(dou.noukn)
from dou
join v_kzeiritsu on
dou.zeiritsu = v_kzeiritsu.zeiritsu
)) as noukn2;
Just move your sum logic inside select as follows:
(SELECT SUM(DOU$2.NOUKN)
FROM SDNISHI.V_KZEIRITSU V
WHERE DOU$2.ZEIRITSU = V.ZEIRITSU) AS NOUKN2
In case If it gives aggregation error then use sum(above query) AS NOUKN2
Your code is very strange. For instance, it seems to assume that V_KZEIRITSU has one row. But, you can move this to the FROM clause:
SELECT SUM(CASE WHEN DOU.ZEIRITSU = K.ZEIRITSU THEN DOU.NOUKN ELSE 0 END) AS NOUKN2
FROM DOU LEFT JOIN
V_KZEIRITSU K
ON 1=1 -- in case the table is really empty
A slightly more reasonable version would be:
SELECT SUM(DOU.NOUKN) AS NOUKN2
FROM DOU LEFT JOIN
V_KZEIRITSU K
ON DOU.ZEIRITSU = K.ZEIRITSU -- in case the table is really empty
It seems rather unlikely to me that this is what you really intend. If not, I would suggest that you ask a new question with appropriate same data, desired results, and explanation of the results. A non-working query should not be expected to provide the same level of information.
I'd say that it is, actually, as simple as
select sum(dou.noukn)
from dou
where dou.zeiritsu in (select zeiritsu from v_kzeiritsu)
(I'm not sure what dou is (table? alias?), but I hope you do.)
After you edited the question, I'm editing the answer. I marked with "--> this" two lines that - in my opinion - might help. As previously, the whole sum(case ...) as noukn2 is replaced by a simple sum(dou$2.noukn).
Note that - in Oracle - you can't use as keyword for table alias. For example:
no: from employees as e
yes: from employees e
Here's your query:
SELECT DOU$2.CUSTCD AS CUSTCD,
DOU$2.CHUNO AS CHUNO,
DOU$2.LINNO AS LINNO,
DOU$2.SHIPDAYYM AS SHIPDAYYM,
SUM (DOU$2.NOUKN) AS NOUKN,
SUM (DOU$2.ZEIKN) AS ZEIKN,
SUM (dou$2.noukn) AS noukn2 --> this
FROM SDNISHI.T_HCHUMON_DOUSOU DOU$2
INNER JOIN SDNISHI.SY_KANRI KNR ON KNR.SHIPDAYYM = DOU$2.SHIPDAYYM
INNER JOIN SDNISHI.T_HCHUMON_MEI MEI
ON MEI.CUSTCD = DOU$2.CUSTCD
AND MEI.CHUNO = DOU$2.CHUNO
AND MEI.LINNO = DOU$2.LINNO
AND MEI.SHIPDAYYM = DOU$2.SHIPDAYYM
AND MEI.USEDNGKBN = '0'
AND MEI.CANCELKBN = '0'
LEFT OUTER JOIN SDNISHI.T_HCHUMON_HD HD
ON HD.CUSTCD = MEI.CUSTCD
AND HD.CHUNO = MEI.CHUNO
AND HD.LINNO = MEI.LINNO
AND HD.USEDNGKBN = '0'
AND HD.CANCELKBN = '0'
AND isnull (HD.CANKBN, '00') = '00'
JOIN v_keziritsu vk ON vk.zeiritsu = dou$2.zeiritsu --> this
WHERE DOU$2.USEDNGKBN = '0'
AND DOU$2.CANCELKBN = '0'
AND ( ( MEI.CHGDELKBN = '1'
AND MEI.HDOUSOUKBN = '02'
AND ( MEI.CHUSU > 0
OR MEI.BCHUSU > 0))
OR ( MEI.CHGDELKBN != '1'
AND HD.HDOUSOUKBN = '02'
AND ( MEI.CHKBTNFGA = '1'
AND HD.CHUSU > 0)
OR ( MEI.CHKBTNFGB = '1'
AND HD.BCHUSU > 0)))
GROUP BY DOU$2.CUSTCD,
DOU$2.CHUNO,
DOU$2.LINNO,
DOU$2.SHIPDAYYM

TSQL - Multiple Values in INSERT (because of joins)

Im trying to insert a data from one database to another. This is what i have so far, on the select side:
USE [db2]
SELECT
sP.pers_FirstName
,sp.pers_LastName
,sPH.Phon_Number
,CASE WHEN LEFT(sPH.Phon_Number, 2) = '04' THEN sPH.Phon_number ELSE NULL END
,CASE WHEN sp.pers_gender = 1 THEN 'M' WHEN sp.pers_gender = 2 THEN 'F' ELSE 'U' END
,CASE
WHEN sP.pers_salutation = '10' THEN 8
WHEN sp.pers_salutation = '6' THEN 2
WHEN sp.pers_salutation = '7' THEN 1
WHEN sp.pers_salutation = '8' THEN 4
WHEN sp.pers_salutation = '9' THEN 5
WHEN sp.pers_salutation = 'APROF' THEN 6
WHEN sp.pers_salutation = 'Ms.' THEN 4
WHEN sp.pers_salutation = 'PROF' THEN 6
END
,sp.pers_dob
,sp.pers_CreatedDate
,sp.pers_UpdatedDate
,'Candidate'
,1
,e.Emai_EmailAddress
,sP.pers_personID
FROM [db1].dbo.person sP
LEFT JOIN [db1].dbo.PhoneLink sPL ON sp.pers_personID = sPL.PLink_recordID
LEFT JOIN [db1].dbo.Phone sPH ON sPL.PLink_PhoneId = sPH.Phon_PhoneID
LEFT JOIN [db1].dbo.EmailLink eL ON sP.pers_personID = eL.ELink_RecordID
LEFT JOIN [db1].dbo.Email e ON eL.Elink_EmailID = e.Emai_EmailID
WHERE
(
sP.pers_employedby NOT IN (
'Aspen'
,'ACH'
)
)
OR
(
sP.pers_employedby IN (
'Aspen'
,'ACH'
)
AND sP.pers_personID NOT IN (
SELECT c.oppo_PrimaryPersonID FROM [SageCRM].dbo.Opportunity c
WHERE (c.oppo_contractcompleted <= '2016-01-01' OR c.oppo_contractterminated <= '2016-01-01') and c.Oppo_Deleted is null)
AND
sp.pers_isanemployee != 'ECHO'
AND sP.pers_personID IN (
SELECT c.oppo_PrimaryPersonID FROM [SageCRM].dbo.Opportunity c
WHERE c.oppo_Status != 'In Progress' OR c.oppo_Status = 'Completed')
AND sP.pers_dod IS NULL
AND sP.pers_FirstName NOT LIKE '%test%'
AND sP.pers_LastName NOT LIKE '%test%'
AND sp.pers_isanemployee != 'SalesContact'
)
Due to the fact that each person record can have multiple phone numbers linked to them, i end up with multiple records for each person, which obviously wont work as i will end up with duplicates when i actually insert the data.
The problem is, that i need to have all of the phone numbers for each record, just displayed in a different field (home phone, work phone, mobile phone).
Any Ideas, other than doing this in a separate insert statement for each phone / email link?
-------- EDIT: -----------------------------------------------------------------
Ok so, my bad for not giving you enough information. Both of your answers were good answers so thanks for that (#Horaciux, #John Wu).
However, there is no phoneType column, just a phone number. That being said, since every mobile starts with 04 and every home phone with anything else, i can pretty easily distinguish between the two phone types.
There are duplicates in the phone table though, so i will have to delete these, most likely via CTE, shouldn't be too hard.
So, i will end up with something like this for the two phone numbers:
SELECT (phon_number FROM phone p INNER JOIN PhoneLink p1 on p1.PhoneLinkID = p.PhoneLink WHERE LEFT(p.Phon_Number, 2) = '04')
SELECT (phon_number FROM phone p INNER JOIN PhoneLink p1 on p1.PhoneLinkID = p.PhoneLink WHERE LEFT(p.Phon_Number, 2) != '04')
My duplicate removal will be something like this:
WITH CTE AS
(
SELECT phon_linkID, phon_phonNumber, ROW_NUMBER() OVER (PARTITION BY phon_phonNumber ORDER BY phon_linkID) AS RN
FROM phone
)
DELETE FROM CTE WHERE RN<>1
Two easy steps.
Get rid of the joins to the phone number table.
Lookup the phone numbers per record by using a subquery in the select clause, one for each type of phone. Example
SELECT sP.pers_FirstName,
sP.pers_LastName,
(SELECT Phon_Number FROM Phone p JOIN PhoneLink pl ON pl.PhoneLinkID = p.PhoneLinkID WHERE pl.Person_ID = sP.pers_personID AND pl.Type = 'WORK') WorkPhone,
(SELECT Phon_Number FROM Phone p JOIN PhoneLink pl ON pl.PhoneLinkID = p.PhoneLinkID WHERE pl.Person_ID = sP.pers_personID AND pl.Type = 'HOME') HomePhone
FROM person
Without knowing your table's structure, I'll do some example.
select person.id,
max(case when phone.type='home' then phone.vlaue else 0 end) 'home',
max(case when phone.type='work' then phone.vlaue else 0 end) 'work'
from person,phone where...
group by person.id
Then use this query to join all other tables needed

Incorrect Count Using Self Join

I'm attempting to get a Count of how many times each book occurs in the SurveyDatas table for a each grade and each survey year.
In the query below the result in the Grade3 column for BookId 300 should actually be 1, but instead its 116. And same for the Grade4 column too. If I remove the Grade4 Count and JOIN, I get 58 which is half of 116, but still incorrect. I'm suspicious I need to use a Subquery instead of Left Joins for what I'm trying to do here, or perhaps there's even a more efficient way of doing this. Would SQL Server Common Table Expressions help me out here? I've never used that feature.
SELECT sd.SurveyYear, sd.BookId,
Count(sd3.Grade) as Grade3, Count(sd4.Grade) as Grade4
FROM SurveyDatas sd
LEFT JOIN SurveyDatas sd3 on sd3.BookId = sd.BookId
AND sd3.SurveyYear = sd.SurveyYear
AND sd3.Grade = '3'
LEFT JOIN SurveyDatas sd4 on sd4.BookId = sd.BookId
AND sd4.SurveyYear = sd.SurveyYear
AND sd4.Grade = '4'
GROUP BY sd.SurveyYear, sd.BookId
And here's my table structure and what my data looks like, although I do have more data entered than what I'm showing here.
SurveyDataId | SurveyYear | BookId | Grade
1 2014 300 3
2 2014 300 4
You are getting a cartesian product between the two. Instead, just use conditional aggregation:
SELECT sd.SurveyYear, sd.BookId,
sum(case when sd.Grade = '3' then 1 else 0 end) as Grade3,
sum(case when sd.Grade = '4' then 1 else 0 end) as Grade4
FROM SurveyDatas sd
GROUP BY sd.SurveyYear, sd.BookId;
The self-join is not necessary.
When you self join, you need to consider all columns. You aren't using the SurverDataID, and not getting the full picture because of it. Include it in you join condition, and you'll see what you expect.
SELECT sd.SurveyYear, sd.BookId,
Count(sd3.Grade) as Grade3, Count(sd4.Grade) as Grade4
FROM SurveyDatas sd
LEFT JOIN SurveyDatas sd3 on sd3.BookId = sd.BookId
AND sd3.SurveyYear = sd.SurveyYear
AND sd3.Grade = '3'
AND sd.SurveyDataID = sd3.SurveyDataID -- Add this line
LEFT JOIN SurveyDatas sd4 on sd4.BookId = sd.BookId
AND sd4.SurveyYear = sd.SurveyYear
AND sd4.Grade = '4'
AND sd.SurveyDataID = sd4.SurveyDataID -- And also this line
GROUP BY sd.SurveyYear, sd.BookId
When I was trouble shooting it, I removed the group by so that I could see all the rows. I should have seen nulls for Grade 4 where the survey was for Grade 3, and that tipped me off to the real cause.

Want to filter SQL Server query

Currently I am pulling out the Facilities where the permitType is 'Hazardous waste' and the licenseStatus is 'Open', but there will be cases where the facilities will have more than one permit type suppose a facility can have two permit types
Hazardous waste (status - OPEN)
AST (OPEN)
so I should not display this facility in my output if it other permit types (Status - OPEN) apart from the 'hazardous waste', but if the other permit type has status - CLOSE then my query should output the Facility i.e if AST(Status - CLOSE) then the facility should be pulled from the database.
I wrote the following query but not sure where to include the condition.
SELECT
e.facilityID
,f.organization_core AS 'Facility Name'
,f.address_full_core AS 'Facility Address'
,a.permitNumber AS 'Permit Number'
,b.permitName AS 'Permit Name'
,a.licenseStatus AS 'Permit Status'
,c.permitType AS 'Permit Type'
FROM
tblPermits a
LEFT JOIN
dbo.tblPermit_Names b ON a.permitID = b.permitID
LEFT JOIN
dbo.tblLKP_Permit_Facilities d ON a.permitID = d.permitID
LEFT JOIN
dbo.tblPermit_Types c ON a.permitTypeID = c.permitTypeID
LEFT JOIN
dbo.tblFacility e ON d.facilityID = e.facilityID
LEFT JOIN
dbo.tblAddresses f ON e.facilityAddressID = f.addressID
WHERE
a.permitTypeID IN (SELECT permitTypeID
FROM dbo.tblPermit_Types
WHERE permitType IN ('Hazardous Waste'))
AND a.licenseStatus = 'Open'
AND isNull(a.deleted, 0) = 0
I think the following query implements your rules. The idea is to focus on the facility and not on all the extra stuff in the tables that you have put in. You need to aggregate by facilityid so you can apply logic to all the permits issued for each one:
SELECT f.facilityID
FROM dbo.tblFacility f join
dbo.tblLKP_Permit_Facilities pf
on pf.facilityID = f.facilityId join
tblPermits p
on pf.permitID = p.permitID join
dbo.tblPermit_Types pt
ON pt.permitTypeID = p.permitTypeID
GROUP BY f.facilityID
HAVING SUM(case when pt.permitType IN ('Hazardous Waste') and p.licenseStatus = 'Open'
then 1 else 0
end) > 0 and
SUM(case when pt.permitType NOT IN ('Hazardous Waste') and p.licenseStatus = 'Close'
then 1 else 0
end) > 0;
Each condition in the having clause is applying one of your rules.
I'm a little confused as to your table structure, but this is what I think you should do.
Your where statement should be id in (Select id from table where status = open and count(id) = 1 group by facility)
AND Type in ('Hazardous Waste')
The first part of the where statement will limit all ids to those that are open with only one open type per facility, the second part limits it to just hazardous waste.
If you have a facility with 10 permits, but only one is active, it will pull it into the list, but if the active permit isn't hazardous waste, it will then exclude it.
Sorry I can't give you exact code.
Also, nix as many of those outer joins as you can. Inner joins are faster, and are more likely to represent the data you want.

Extracting null fields in SQL Server

I will try to be as detailed as possible. Our corporate controller has asked me for some information regarding our suppliers. Here are the tables:
spp = supplier table, each supplier has one record, there are 5,222 records
ast = supplier account profile, there is a (M, 1) relationship between this table and spp, there are 8,950 records in this table. Each duplicate spp_id has a different atp_id which is a transaction profile.
crt = bank account information, a supplier may or may not have bank account info
xvd = table of checking tables, xvd.xcd_id is the field that holds the checking table id. Checking table 0007 is the table that contains the discount info.
Here is my script:
select spp.spp_id supp_num,
spp.spp_matchname supp_name,
case when spp.spp_ddcalculation = 0
then 'End of Month'
else
case when spp.spp_ddcalculation = 1
then 'Net'
else
case when spp.spp_ddcalculation = 2
then 'End of 10, 20, 30'
else
case when spp.spp_ddcalculation = 3
then 'End of 15 or 30'
else null
end
end
end
end calculation1,
convert(varchar(2), spp.spp_ddduration) + case when spp.spp_ddmd = 0
then ' Days'
else case when spp.spp_ddmd = 1
then ' Months'
else null
end
end duration1,
spp.spp_ddday stop_day1,
xvd.xvd_desc discount,
crt.crt_name bank,
case when ast.ast_ddcalculation = 0
then 'End of Month'
else
case when ast.ast_ddcalculation = 1
then 'Net'
else
case when ast.ast_ddcalculation = 2
then 'End of 10, 20, 30'
else case when ast.ast_ddcalculation = 3
then 'End of 15 or 30'
else null
end
end
end
end
calculation2,
convert(varchar(2), ast.ast_ddduration) + case when ast.ast_ddmd = 0
then ' Days'
else case when ast.ast_ddmd = 1
then ' Months'
else null
end
end
duration2,
ast.ast_ddday stop_day2
from spp left join ast on spp.spp_id = ast.spp_id
left join crt on ast.crt_id = crt.crt_id
inner join xvd on ast.cfd_id = xvd.xcv_id
where xvd.xcd_id = '0007'
and xvd.lng_id = 0
order by spp.spp_id
The problem is that there are 371 records in the ast table that have a non null cfd_id which is the field that relates to the discount in checking table 0007. When I run this I get 371 records, but I need all suppliers, even those with null discounts. I know the problem is a combination of my joins and the fact that there is not a null xcv_id in checking table 0007. Can anyone see anything glaring that I have overlooked?
To recap, there are 8,950 records in ast, but only 371 of them have a non null cfd_id. I need to grab all 8,950 records, I can't seem to extract the null discounts. I think I can probably pull everything into a temp table then grab the discounts, but am wondering if there is a way to do this in one select statement.
Thanks
Tony
Edit: The last line of my from statement seems to be the primary issue
inner join xvd on ast.cfd_id = xvd.xcv_id
There are no null xcv_id but there are null cfd_id. Is there another way to join those two tables, besides checking for equality?
Forgot to mention, we are on SQL Server 2008 R2.
Does this solve the problem ?
FROM spp
LEFT JOIN ast
ON spp.spp_id = ast.spp_id
LEFT JOIN crt
ON ast.crt_id = crt.crt_id
INNER JOIN xvd
ON xvd.xcv_id = ast.cfd_id
WHERE xvd.xcd_id = '0007'
AND xvd.lng_id = 0
I think you can just change your inner join to a left join:
from spp left join ast on spp.spp_id = ast.spp_id
left join crt on ast.crt_id = crt.crt_id
inner join xvd on ast.cfd_id = xvd.xcv_id
to
from spp left join ast on spp.spp_id = ast.spp_id
left join crt on ast.crt_id = crt.crt_id
left join xvd on ast.cfd_id = xvd.xcv_id
If you are saying that you want to select records where xvd.xcd_id is 0007 or null then change your where clause to this:
(xvd.xcd_id = '0007' OR xvd.xcd_id is null)
This sounds like a perfect use for views. Instead of trying to build one complex query, you could build a series of views that build upon one another filtering the data the way you want it... then apply the final query to the last view.