I have a table like
City POSTAGE PRICE**
HOUSTON DEFAULT 20
DEFAULT AIR 14
DEFAULT GROUND 30
DEFAULT DEFAULT 40
Now i want to query for price on this table with a combination like 'CHICAGO,GROUND'
which should check if the perfect combination exists, else i should substitute DEFAULT and search for the value..
example,
HOUSTON,AIR should return 14
HOUSTON,GROUND should return 20
HOUSTON,FEDEX should return 20
CHICAGO,FEDEX should return 40
Is there a way to achieve this instead of writing multiple queries ..
thank you!
This uses the SQL*Plus syntax for passing parameters, you may need to change that to suit:
select price
from your_table
where ( city = '&p_city' or city = 'DEFAULT')
and ( postage = '&p_postage' or postage = 'DEFAULT')
order by case when city = '&p_city' then 1 else 2 end
, case when postage = '&p_postage' then 1 else 2 end
This will return multiple rows but presumably you want only the one PRICE. The ORDER BY clause prioritises matches on CITY over matches on POSTAGE. You can then select the first row.
Related
Let's say I have a dimension and a fact table:
SELECT
LAST_DAY(TO_Date((f.Date),'MON-YYYY')) "MonthYear",
f.Region,
d.Formula as "Molecule",
d.product_name,
d.supplier.
SUM(f.Sales) as "Sales",
SUM(f.ext_units) as "ext_Units",
SUM(f.units) "Units",
SUM(f.ext_units) / SUM(f.units) as "Product_units"
CASE
WHEN d.Formula = 'ABC:CBA' THEN 'ABC'
WHEN d.Formula = 'DEF-FED' THEN 'DEF'
WHEN d.Formula = 'xyz;zyx' THEN 'xyz'
ELSE d.Formula
END AS "Molecule"
FROM Fact.Sales f
INNER JOIN DM_Product d on f.P-Code = d.P-Code
WHERE
f.Region = 'Mars'
AND d.Supplier = 'Simpsons'
AND d.Formula in ('ABC','DEF','GHI','JKL','BDHJK',
'FGL','MNP','RSTU', 'KCL', 'xyz', 'UWX',
'xyz;zyx', 'DEF-FED', 'ABC:CBA')
GROUP BY f.Date,
f.Region,
d.Formula,
d.product_name,
d.supplier
so, basically what I intend to do is to get all these Molecules from the Product Dimension table and find their relevant sales. but the puzzle is I have two different set of conditions:
to look into to all the two syllabuses formulas and aggregate them with equivalent one syllabi formula to find aggregate sales.
Find "Product_units" using SUM(f.ext_units) / SUM(f.units) as per my code.
(f.units) does have 0 values.
As I put for the 1st condition, I used CASE WHEN and it works perfect to find the 2 syllabuses formulas and plug them to relevant 1 syllabi formula but for the second condition that I need to know how to make sure that f.units <> 0 that is checking if SUM(f.units) <> 0 THEN SUM(f.ext_units) /SUM(f.units) ELSE 0 ?
I have a column (text) in my Postgres DB (v.10) with a JSON format.
As far as i now it's has an array format.
Here is an fiddle example: Fiddle
If table1 = persons and change_type = create then i only want to return the name and firstname concatenated as one field and clear the rest of the text.
Output should be like this:
id table1 did execution_date change_type attr context_data
1 Persons 1 2021-01-01 Create Name [["+","name","Leon Bill"]]
1 Persons 2 2021-01-01 Update Firt_name [["+","cur_nr","12345"],["+","art_cd","1"],["+","name","Leon"],["+","versand_art",null],["+","email",null],["+","firstname","Bill"],["+","code_cd",null]]
1 Users 3 2021-01-01 Create Street [["+","cur_nr","12345"],["+","art_cd","1"],["+","name","Leon"],["+","versand_art",null],["+","email",null],["+","firstname","Bill"],["+","code_cd",null]]
Disassemble json array into SETOF using json_array_elements function, then assemble it back into structure you want.
select m.*
, case
when m.table1 = 'Persons' and m.change_type = 'Create'
then (
select '[["+","name",' || to_json(string_agg(a.value->>2,' ' order by a.value->>1 desc))::text || ']]'
from json_array_elements(m.context_data::json) a
where a.value->>1 in ('name','firstname')
)
else m.context_data
end as context_data
from mutations m
modified fiddle
(Note:
utilization of alphabetical ordering of names of required fields is little bit dirty, explicit order by case could improve readability
resulting json is assembled from string literals as much as possible since you didn't specified if "+" should be taken from any of original array elements
the to_json()::text is just for safety against injection
)
I want to select data as per below criteria in Netezza.
can someone help me to write the sql.
Case 1: Unique ID has 2 "."s
Deal ID = Parse from UNIQ_ID. Pos 1 to first "."
E.g.
Unique ID = 0000149844.FXFWD.COIBI_I
Deal ID = 0000149844
Case 2: Unique ID has 1 "."s
Deal ID = Parse from UNIQ_ID. First "." to end
E.g
Unique ID = 25808.1234140AT`enter code here`
Deal ID = 1234140AT
Use "position" function of Netezza to determine the position of ".", Make use of this output in "substr" function to extract required fields.
For Case 1 :
select substr('0000149844.FXFWD.COIBI_I',1,(position('.' in '0000149844.FXFWD.COIBI_I') - 1));
For Case 2 :
select substr('25808.1234140AT',(position('.' in '25808.1234140AT') + 1));
I'm building an application that needs to allow the user to filter a data table according to different filters. So, the user will have three different filter posibilites but he might use only one, or two or the three of them at the same tame.
So, let's say I have the following columns on the table:
ID (int) PK
Sede (int)
Programa (int)
Estado (int)
All of those columns will store numbers, integers. The "ID" column is the primary key, "Sede" stores 1 or 2, "Programa" is any number between 1 and 15, and "Estado" will store numbers between 1 and 13.
The user may filter the data stored in the table using any of those filters (Sede, Programa or Estado). But the might, as well, use two filters, or the three of them at the same time.
The idea is that this application works like the data filters on Excel. I created a simulated table on excel to show what I want to achieve:
This first image shows the whole table, without applying any filter.
Here, the user selected a filter for "Sede" and "Programa" but leaved the "Estado" filter empty. So the query returns the values that are equal to the filter, but leaves the "Estado" filter open, and brings all the records, filering only by "Sede" (1) and "Programa" (6).
In this image, the user only selected the "Estado" filter (5), so it brings all the records that match this criteria, it doesn't matter if "Sede" or "Programa" are empty.
If I use a SELECT clasuse with a WHERE on it, it will work, but only if the three filters have a value:
DECLARE #sede int
DECLARE #programa int
DECLARE #estado int
SET #sede = '1'
SET #programa = '5'
SET #estado = '12'
SELECT * FROM [dbo].[Inscripciones]
WHERE
([dbo].[Inscripciones].[Sede] = #sede)
AND
([dbo].[Inscripciones].[Programa] = #programa)
AND
([dbo].[Inscripciones].[Estado] = #estado)
I also tryed changing the "AND" for a "OR", but I can't get the desired result.
Any help will be highly appreciated!! Thanks!
common problem: try using coalesce on the variable and for the 2nd value use the field name you're comparing to. Be careful though; Ensure it's NULL and not empty string being passed!
What this does is take the first non-null value of the variable passed in or the value you're comparing to.. Thus if the value passed in is null the comparison will always return true.
WHERE
[dbo].[Inscripciones].[Sede] = coalesce(#sede, [dbo].[Inscripciones].[Sede])
AND
[dbo].[Inscripciones].[Programa] = coalesce(#programa, [dbo].[Inscripciones].[Programa])
AND
[dbo].[Inscripciones].[Estado] = coalesce(#estado, [dbo].[Inscripciones].[Estado])
If sede is null and programa and estado are populated the compare would look like...
?=? (or 1=1)
?=programa variable passed in
?=Estado variable passed in
Boa Sorte!
Thank you all for your anwers. After reading the article posted in the comments by #SeanLange I was finally able to achieve what was needed. Using a CASE clause in the WHERE statement solves the deal. Here's the code:
SELECT
*
FROM [dbo].[Inscripciones]
WHERE
([dbo].[Inscripciones].[Sede] = (CASE WHEN #sede = '' THEN [dbo].[Inscripciones].[Sede] ELSE #sede END))
AND
([dbo].[Inscripciones].[Programa] = (CASE WHEN #programa = '' THEN [dbo].[Inscripciones].[Programa] ELSE #programa END))
AND
([dbo].[Inscripciones].[Estado] = (CASE WHEN #estado = '' THEN [dbo].[Inscripciones].[Estado] ELSE #estado END))
AND
([dbo].[Inscripciones].[TipoIngreso] = (CASE WHEN #tipoingreso = '' THEN [dbo].[Inscripciones].[TipoIngreso] ELSE #tipoingreso END))
Thanks again!!
Please let me know if there is any query where in I remove the repeating entries in a row.
For eg: I have a table which has name with 9 telephone numbers:
Name Tel0 Tel1 Tel2 Tel3 Tel4 Tel5 Tel6 Tel7 Tel8
John 1 2 2 2 3 3 4 5 1
The final result should be as shown below:
Name Tel0 Tel1 Tel2 Tel3 Tel4 Tel5 Tel6 Tel7 Tel8
John 1 2 3 4 5
regards
Maddy
I fear that it will be more complicated to keep this format than to split the table in two as I suggested. If you insist on keeping the current schema then I would suggest that you query the row, organise the fields in application code and then perform an update on the database.
You could also try to use SQL UNION operator to give you a list of the numbers, a UNION by default will remove all duplicate rows:
SELECT Name, Tel FROM
(SELECT Name, Tel0 AS Tel FROM Person UNION
SELECT Name, Tel1 FROM Person UNION
SELECT Name, Tel2 FROM Person) ORDER BY Name ;
Which should give you a result set like this:
John|1
John|2
You will then have to step through the result set and saving each number into a separate variable (skipping those variables that do not exist) until the "Name" field changes.
Tel1 := Null; Tel2 := Null;
Name := ResultSet['Name'];
Tel0 := ResultSet['Tel'];
ResultSet.Next();
if (Name == ResultSet['Name']) {
Tel1 := ResultSet['Tel'];
} else {
UPDATE here.
StartAgain;
}
ResultSet.Next();
if (Name == ResultSet['Name']) {
Tel2 := ResultSet['Tel'];
} else {
UPDATE here.
StartAgain;
}
I am not recommending you do this, it is very bad use of a relational database but once implemented in a real language and debugged that should work.