SQL to get the one to many mapping (like reverse CASE WHEN THEN END or decode in Oracle) - sql

For example,
Through "CASE WHEN THEN END" I can get a many-to-one mapping as below.
REGION = CASE WHEN IOG IN (1,2,14,37,72,101) THEN '1'
WHEN IOG IN (11,22,48,77) THEN '7'
WHEN IOG IN (7,13,18,24,39) THEN '3'
ELSE NULL END
Currently, I want get the reverse mapping (one-to-many) which is used in WHERE clause, the logic is like as below (but it's not correct, what I mean is the logic)
CASE WHEN REGION = 1 THEN IOG in (1,2,14,37,72,101)
WHEN REGION = 7 THEN IOG in (11,22,48,77)
WHEN REGION = 3 THEN IOG in (7,13,18,24,39)
ELSE NULL END
There is grammatical mistake in above sql, but how can I make ? Is it possible to get a one-to-many mapping?
One more thing, which I'm using is Oracle DB, seems that it's not available by using "decode" because it's also one-to-one mapping.
Could anyone help with it? Thanks in advance.

Here is another approach:
WHERE (CASE WHEN REGION = 1 and IOG in (1,2,14,37,72,101) then 1
WHEN REGION = 7 and IOG in (11,22,48,77) then 1
WHEN REGION = 3 and IOG in (7,13,18,24,39) then 1
ELSE 0
END) = 1
Or, you can get rid of the case entirely:
WHERE (REGION = 1 and IOG in (1,2,14,37,72,101) ) or
(REGION = 7 and IOG in (11,22,48,77) ) or
(REGION = 3 and IOG in (7,13,18,24,39) )

Add Condition in where and using CASE .. WHEN .. THEN..
TRY TO FOLLOWING WAY..
select col1,col2,...colN..from Table
Where clm1 = CASE WHEN #PARAMETER = 0 THEN COL1 ELSE #PARAMETER
ONCE YOU SET SAME COLUMN NAME INTO WHERE CONDITION THEN YOU RETRIEVE ALL DATA FROM TABLE ELSE IF YOU WANT TO PASS AS PARAMETER THEN RETRIEVE BASE ON CONDITION VALUES FROM TABLE.

Related

How can I update if value is different or empty

I want to update my column if the vlaue is different from last value or its empty. I came up with this sql but it gives this error:
missing FROM-clause entry for table "box_per_pallet"
SQL:
UPDATE products AS p
SET box_per_pallet[0] = (CASE WHEN p.box_per_pallet.length = 0 THEN 0 ELSE p.box_per_pallet[0] END)
WHERE sku = 'A' AND store_id = 1
This is what I came up with based on your input. ARRAY_LENGTH takes the array and the dimension you want to check the length of as parameters. This missing from clause is because Postgres thinks that p.box_per_pallet is something other than an array and it can't find that anywhere in the query. You can't use the dot operator on arrays like p.box_per_pallet.length. It's like saying, "find the length field on table box_per_pallet in schema p".
UPDATE products
SET box_per_pallet[0] = CASE WHEN ARRAY_LENGTH(box_per_pallet, 1) = 0
OR box_per_pallet IS NULL
OR box_per_pallet[0] <> 0 -- your new value?
THEN 0
ELSE box_per_pallet[0]
END
WHERE sku = 'A'
AND store_id = 1
;
Here is a link to a dbfiddle showing the idea.

Using Max(boolean) in a case statement

I am made a temp table of accounts in a database with booleans that provide insight about the accounts. Some customers have multiple accounts so I am grouping them together and was trying to look at the MAX(Boolean) to set a status field.
My query kinda looks like:
with t as (Select lngCustomerNumber,
Case
When 'Criteria for being Active' Then 1
End as blnActive,
Case
When 'Criteria for unexpired' Then 1
End as blnUnexpired
From AccountTable)
Select t.CustomerNumber,
Case
When Max(t.blnActive) = 1
AND Max(t.blnUnexpired) = 1 Then 'Active/Unexpired'
When Max(t.blnActive) = 1
AND Max(t.blnUnexpired) = 0 Then 'Active/Expired'
When Max(t.blnActive) = 0
AND Max(t.blnUnexpired) = 1 Then 'Inactive/Unexpired'
When Max(t.blnActive) = 0
AND Max(t.blnUnexpired) = 0 Then 'Inactive/Expired'
End As strLicenseStatus
From T
Group By t.CustomerNumber
Anything where it checks if the Max(Boolean) = 1 will calc to True correctly, but if I do Max(Boolean) = 0 or Max(Boolean) <> 1 then it does not calc to True when it should.
I have tested by just looking at the grouped Temp Table with each boolean bringing back its Max() value and the ones that should be 0 are coming back as 0.
As a workaround, I have tried
Where t.CustomerNumber NOT IN (SELECT t2.CustomerNumber
FROM t t2
WHERE t2.blnUnexpired = 1
AND t2.CustomerNumber = t.CustomerNumber )
And that does give me the results that I am looking for but I have millions of rows coming back so it has been timing out after many hours, where the previous method was able to run in less than an hour.
I have some other data in my query, the one presented is a much smaller version used to highlight my issue.
Any recommendations on how I can make this work?
Thank you.
When you are defining your blnActive and blnUnexpired cases, you only have the "1" case defined, which means if it doesn't meet these criteria, it will be null. Try adding else 0 to each case:
with t as (Select lngCustomerNumber,
Case
When 'Criteria for being Active' Then 1
Else 0
End as blnActive,
Case
When 'Criteria for unexpired' Then 1
Else 0
End as blnUnexpired
From AccountTable)

Is it possible to use AND in an UPDATE SET clause in a CASE statement?

I need to check two conditions:
1. when the function returns true
2. when the function returns true AND ISP_Program has the word "IRSS" in it
What is the correct syntax? I have the following:
UPDATE [PAYROLL].[dbo].[BILL]
SET Pay_Code = CASE dbo.is_Holiday([BILL].Date)
WHEN 1 THEN holiday_code
WHEN 1 AND ISP_Program like '%IRSS%' THEN '66'
ELSE Pay_Code
END
FROM tbl_TXEX_HOLIDAY
INNER JOIN [BILL] ON [BILL].Pay_Code = tbl_HOLIDAY.regular_code
I think you want:
SET Pay_Code = (CASE WHEN dbo.is_Holiday([BILL].Date) = 1 AND ISP_Program like '%IRSS%' THEN '66'
WHEN dbo.is_Holiday([BILL].Date) = 1 THEN holiday_code
ELSE Pay_Code
END)
Note that the ordering of these conditions is important.
I assume that BILL is the table referenced in the UPDATE. I would recommend writing the complete logic as:
UPDATE b
SET Pay_Code = (CASE WHEN dbo.is_Holiday(b.Date) = 1 AND ISP_Program like '%IRSS%' THEN '66'
WHEN dbo.is_Holiday(b.Date) = 1 THEN holiday_code
ELSE b.Pay_Code
END)
FROM [PAYROLL].[dbo].[BILL] b JOIN
tbl_TXEX_HOLIDAY h
ON b.Pay_Code = h.regular_code;
Notes:
Define aliases for the tables so the query is easier to write and to read.
Use the alias for the update, so it is clear what you intend.
Put the table being updated first. After all, it needs to have matching rows for the update to take place.
Of course, fix the case expression.

Dynamic SQL: CASE expression in HAVING clause for SSRS dataset query

One of my tables contains 6 bit flags:
tblDocumentFact.useCase1
tblDocumentFact.useCase2
tblDocumentFact.useCase3
tblDocumentFact.useCase4
tblDocumentFact.useCase5
tblDocumentFact.useCase6
The bit flags are used to restrict the returned data via a HAVING clause, for example:
HAVING tblDocumentFact.useCase4 = 1 /* '1' means 'True' */
That works in a static query. The query is for a dataset for a SQL Server Reporting Services report. Rather than have 6 reports, one per bit flag, I'd like to have 1 report with an #UserChoice input parameter. I'm trying to write a dynamic query to structure the HAVING clause in accordance with the #UserChoice parameter. I'm thinking that #UserChoice could be set to an integer value (1, 2, 3, 4, 5 or 6) when the user clicks a 1-of-6 option button. I've tried to do this via CASE expressions as shown below, but it doesn't work--the query returns no rows. What's the correct approach here?
HAVING (
(CASE WHEN #UserChoice =1 THEN 'dbo.tblDocumentFact.useCase1' END) = '1'
OR (CASE WHEN #UserChoice =2 THEN 'dbo.tblDocumentFact.useCase2' END) = '1'
OR (CASE WHEN #UserChoice =3 THEN 'dbo.tblDocumentFact.useCase3' END) = '1'
OR (CASE WHEN #UserChoice =4 THEN 'dbo.tblDocumentFact.useCase4' END) = '1'
OR (CASE WHEN #UserChoice =5 THEN 'dbo.tblDocumentFact.useCase5' END) = '1'
OR (CASE WHEN #UserChoice =6 THEN 'dbo.tblDocumentFact.useCase6' END) = '1'
)
You need to rephrase your logic slightly:
HAVING
(#UserChoice = 1 AND 'dbo.tblDocumentFact.useCase1' = '1') OR
(#UserChoice = 2 AND 'dbo.tblDocumentFact.useCase2' = '2') OR
(#UserChoice = 3 AND 'dbo.tblDocumentFact.useCase3' = '3') OR
(#UserChoice = 4 AND 'dbo.tblDocumentFact.useCase4' = '4') OR
(#UserChoice = 5 AND 'dbo.tblDocumentFact.useCase5' = '5') OR
(#UserChoice = 6 AND 'dbo.tblDocumentFact.useCase6' = '6');
A CASE expression can't be used in the way you were using it, because what follows THEN or ELSE has to be a literal value, not a logical condition.
To expand a bit on the comment under Tim's post, I think the reason it doesn't work out is because your cases are emitting strings containing column names not the values of columns
HAVING
CASE WHEN #UserChoice = 1 THEN dbo.tblDocumentFact.useCase1 END = 1
OR CASE WHEN #UserChoice = 2 THEN dbo.tblDocumentFact.useCase2 END = 1
...
It might even clean up to this:
HAVING
CASE #UserChoice
WHEN 1 THEN dbo.tblDocumentFact.useCase1
WHEN 2 THEN dbo.tblDocumentFact.useCase2
...
END = 1
The problem (I believe; in sql server at least, not totally sure about SSRS) is that when you say:
CASE WHEN #UserChoice = 1 THEN 'dbo.tblDocumentFact.useCase1' END = '1'
Your case when is emitting the literal string dbo.tblDocumentFact.useCase1 not the value of that column on that row. And of course this literal string is never equal to a literal string of 1
Overall I prefer Tim's solution; I think the query optimizer will more likely be able to use an index on the bit columns in that form, but be aware that use of ORs can cause sql server to ignore indexes; the DBAs at my old place frequently rewrote queries like:
SELECT * FROM Person WHERE FirstName = 'john' OR LastName = 'Smith'
Into this:
SELECT * FROM Person WHERE FirstName = 'john'
UNION
SELECT * FROM Person WHERE LastName = 'Smith'
Because the server wouldn't combine the index on FirstName and the other index on LastName when we used OR, but it would parallel execute using both indexes in the UNION form
Consider as an alternative, combining those bit flags into a single integer, either as a binary 2's complement (if you want to be able to say user choice 1 and 2 by searching for 3 or choice 2 and 4 and 6 by searching 42 [2^(2 -1) + 2^(4-1) + 2^(6-1)]) or just a straight int you can compare to #userChoice, and indexing it

Hive query with except conditions

I am trying to build a hive query that does only the below features or a combination of these features. For example, the features include
name = "summary"
name = "details"
name1 = "vehicle stats"
Basically, the query should exclude all the other features in name and name1.
I am quite new to hive. In sql, i know this can be done using except keyword. Just wondering whether there is some functions that can achieve the same.
Thanks very much !!
If I understand correctly, I approach this using group by and having:
select ?
from t
group by ?
having sum(case when name = 'summary' then 1 else 0 end) > 0 and
sum(case when name = 'details' then 1 else 0 end) > 0 and
sum(case when name1 = 'vehicle_stats' then 1 else 0 end) > 0;
The ? is for the column that you want the summary of.