InterBase select for 2 related tables - select

I have the following tables
ControlTypeColorsStyle as T1
ControlType Char 10
ColorsStyleName Char 10
FillColorName Char 20
StrokeColorName Char 20
ColorNameColorHex as T2
ColorName Char 20
ColorHex Char 10
My goal is to get the following table
ColorHexForColorTypeAndColorsStyle as T3
ControlType Char 10
ColorsStyleName Char 10
FillColorName Char 20
FillColorHex Char 10
StrokeColorName Char 20
StrokeColorHex Char 10
Where T1.FillColorName, T1.StrokeColorname are foreign keys to T2.ColorName.
I've tried the following statement
select "ControlType", "ColorStyleName",
"ColorName" ,
"ColorHex"
from "ControlTypeColorsStyle" T1,
"ColorNameColorHex" T2
where T1."ControlType" = :pvControlType and
T1."ColorStyleName" = :pvControlStyleName and
T1."FillColorName" = T2."ColorName" and
T1."StrokeColorName" = T2."ColorName"
which returns null values.
I appreciate if anyone can help me.

You need to join your T1 table to 2 copies of the ColorNameColorHex table. Your original SQL would only work when FillColorName and StrokeColorName were the same value. If they are different values and trying to just a single link to the lookup table they will always have one of the two resolve to false hence no records coming back.
For example, if FillColorName is 'red' and StrokeColorName 'black' you do not have a single record in the ColorNameColorHex table that is both 'red' and 'black' at the same time.
You need the second reference to your lookup table so you can translate the FillColorName to its hex value and the second instance of the lookup is used to resolve StrokeColorName to its hex value.
Try
select "ControlType", "ColorStyleName",
"ColorName" ,
T2."ColorHex" "FillColorHex",
T3."ColorHex" "StrokeColorHex"
from "ControlTypeColorsStyle" T1,
"ColorNameColorHex" T2,
"ColorNameColorHex" T3
where T1."ControlType" = :pvControlType and
T1."ColorStyleName" = :pvControlStyleName and
T1."FillColorName" = T2."ColorName" and
T1."StrokeColorName" = T3."ColorName"

Assuming, you setup your table with the correct Primary Key and Foreign Key definitions, you can add matching WHERE conditions to lookup the hex value for the color name from the primary table.
create table ColorNameColorHex (
ColorName char(20) not null PRIMARY KEY,
ColorHex char(10) not null
);
create table ControlTypeColorsStyle (
ControlType char(10),
ColorsStyleName char(10),
FillColorName char(20) REFERENCES ColorNameColorHex(ColorName),
StrokeColorName char(20) REFERENCES ColorNameColorHex(ColorName)
);
and your sample data is...
select * from ColorNameColorHex;
COLORNAME COLORHEX
==================== ==========
LIME #00FF00
CYAN #00FFFF
ORANGERED #FF4500
CHOCOLATE #D2691E
select * from ControlTypeColorsStyle;
CONTROLTYPE COLORSSTYLENAME FILLCOLORNAME STROKECOLORNAME
=========== =============== ==================== ====================
FG BOLD LIME ORANGERED
BG SHADE CYAN ORANGERED
FG BOLD LIME CHOCOLATE
BG SHADE CHOCOLATE ORANGERED
you can write your query as below. For each value in the FillColorName and StrokeColorName columns from ControlTypeColorsStyle table, the WHERE condition matches it up the proper record from ColorNameColorHex.
/* implicit join of the tables */
select ControlType, ColorsStyleName,
T1.FillColorName,
T2.ColorHex FillColorHex,
T1.StrokeColorName,
T3.ColorHex StrokeColorHex
from ControlTypeColorsStyle T1,
ColorNameColorHex T2,
ColorNameColorHex T3
where T1.FillColorName = T2.ColorName and
T1.StrokeColorName = T3.ColorName;
Alternatively, you can use column level sub-queries as follows...
/* column sub-queries */
select ControlType, ColorsStyleName,
FillColorName,
(select ColorHex from ColorNameColorHex where ColorName=T1.FillColorName) FillColorHex,
StrokeColorName,
(select ColorHex from ColorNameColorHex where ColorName=T1.StrokeColorName) StrokeColorHex
from ControlTypeColorsStyle T1;
Output data is...
CONTROLTYPE COLORSSTYLENAME FILLCOLORNAME FILLCOLORHEX STROKECOLORNAME STROKECOLORHEX
=========== =============== ==================== ============ ==================== ==============
FG BOLD LIME #00FF00 ORANGERED #FF4500
BG SHADE CYAN #00FFFF ORANGERED #FF4500
FG BOLD LIME #00FF00 CHOCOLATE #D2691E
BG SHADE CHOCOLATE #D2691E ORANGERED #FF4500

Related

Add ORDINALITY to expanded JSON array in Postgres 11.7

I'm taking two JSONB arrays, unpacking them, and combing the results. I'm trying to add WITH ORDINALITY to the JSON array unpacking. I've been unable to figure out how to add WITH ORDINALITY. For some reason, I can't find WITH ORDINALITY in the documentation for Postgres 11's JSON tools:
https://www.postgresql.org/docs/11/functions-json.html
I've seen examples using jsonb_array_elements....WITH ORDINALITY, but haven't been able to get it to work. First, a functional example based on Postgres arrays:
WITH
first AS (
SELECT * FROM
UNNEST (ARRAY['Charles','Jane','George','Percy']) WITH ORDINALITY AS x(name_, index)
),
last AS (
SELECT * FROM
UNNEST (ARRAY['Dickens','Austen','Eliot']) WITH ORDINALITY AS y(name_, index)
)
SELECT first.name_ AS first_name,
last.name_ AS last_name
FROM first
JOIN last ON (last.index = first.index)
This gives the desired output:
first_name last_name
Charles Dickens
Jane Austen
George Eliot
I'm using the ORDINALITY index to make the JOIN, as I'm combining two lists for pair-wise comparison. I can assume my lists are equally sized.
However, my input is going to be a JSON array, not a Postgres array. I've got the unpacking working with jsonb_to_recordset, but have not got the ordinality generation working. Here's a sample that does the unpacking part correctly:
DROP FUNCTION IF EXISTS tools.try_ordinality (jsonb, jsonb);
CREATE OR REPLACE FUNCTION tools.try_ordinality (
base_jsonb_in jsonb,
comparison_jsonb_in jsonb)
RETURNS TABLE (
base_text citext,
base_id citext,
comparison_text citext,
comparison_id citext)
AS $BODY$
BEGIN
RETURN QUERY
WITH
base_expanded AS (
select *
from jsonb_to_recordset (
base_jsonb_in)
AS base_unpacked (text citext, id citext)
),
comparison_expanded AS (
select *
from jsonb_to_recordset (
comparison_jsonb_in)
AS comparison_unpacked (text citext, id citext)
),
combined_lists AS (
select base_expanded.text AS base_text,
base_expanded.id AS base_id,
comparison_expanded.text AS comparison_text,
comparison_expanded.id AS comparison_id
from base_expanded,
comparison_expanded
)
select *
from combined_lists;
END
$BODY$
LANGUAGE plpgsql;
select * from try_ordinality (
'[
{"text":"Fuzzy Green Bunny","id":"1"},
{"text":"Small Gray Turtle","id":"2"}
]',
'[
{"text":"Red Large Special","id":"3"},
{"text":"Blue Small","id":"4"},
{"text":"Green Medium Special","id":"5"}
]'
);
But that's a CROSS JOIN
base_text base_id comparison_text comparison_id
Fuzzy Green Bunny 1 Red Large Special 3
Fuzzy Green Bunny 1 Blue Small 4
Fuzzy Green Bunny 1 Green Medium Special 5
Small Gray Turtle 2 Red Large Special 3
Small Gray Turtle 2 Blue Small 4
Small Gray Turtle 2 Green Medium Special 5
I'm after a pair-wise result with only two rows:
Fuzzy Green Bunny 1 Red Large Special 3
Small Gray Turtle 2 Blue Small 4
I've tried switching to jsonb_array_elements, as in this snippet:
WITH
base_expanded AS (
select *
from jsonb_array_elements (
base_jsonb_in)
AS base_unpacked (text citext, id citext)
),
I get back
ERROR: a column definition list is only allowed for functions returning "record"
Is there a straightforward way to get ordinality on an unpacked JSON array? It's very easy with UNNEST on a Postgres array.
I'm happy to learn I've screwed up the syntax.
I can CREATE TYPE, if it's of any help.
I can convert to a Postgres array, if that's straightforward to do.
Thanks for any suggestions.
You do it exactly the same way.
with first as (
select *
from jsonb_array_elements('[
{"text":"Fuzzy Green Bunny","id":"1"},
{"text":"Small Gray Turtle","id":"2"}
]'::jsonb) with ordinality as f(element, idx)
), last as (
select *
from jsonb_array_elements('[
{"text":"Red Large Special","id":"3"},
{"text":"Blue Small","id":"4"},
{"text":"Green Medium Special","id":"5"}
]'::jsonb) with ordinality as f(element, idx)
)
SELECT first.element ->> 'text' AS first_name,
last.element ->> 'text' AS last_name
FROM first
JOIN last ON last.idx = first.idx

Update Multiple Columns in One Statement Based On a Field with the Same Value as the Column Name

Not sure if this is possible without some sort of Dynamic SQL or a Pivot (which I want to stay away from)... I have a report that displays total counts for various types/ various status combinations... These types and statuses are always going to be the same and present on the report, so returning no data for a specific combination yields a zero. As of right now there are only three caseTypes (Vegetation, BOA, and Zoning) and 8 statusTypes (see below).
I am first setting up the skeleton of the report using a temp table. I have been careful to name the temp table columns the same as what the "statusType" column will contain in my second table "#ReportData". Is there a way to update the different columns in "#FormattedData" based on the value of the "statusType" column in my second table?
Creation of Formatted Table (for report):
CREATE TABLE #FormattedReport (
caseType VARCHAR(50)
, underInvestigation INT NOT NULL DEFAULT 0
, closed INT NOT NULL DEFAULT 0
, closedDPW INT NOT NULL DEFAULT 0
, unsubtantiated INT NOT NULL DEFAULT 0
, currentlyMonitored INT NOT NULL DEFAULT 0
, judicialProceedings INT NOT NULL DEFAULT 0
, pendingCourtAction INT NOT NULL DEFAULT 0
, other INT NOT NULL DEFAULT 0
)
INSERT INTO #FormattedReport (caseType) VALUES ('Vegetation')
INSERT INTO #FormattedReport (caseType) VALUES ('BOA')
INSERT INTO #FormattedReport (caseType) VALUES ('Zoning')
Creation of Data Table (to populate #FormattedReport):
SELECT B.Name AS caseType, C.Name AS StatusType, COUNT(*) AS Amount
INTO #ReportData
FROM table1 A
INNER JOIN table2 B ...
INNER JOIN table3 C ...
WHERE ...
GROUP BY B.Name, C.Name
CURRENT Update Statement (Currently will be 1 update per column in #FormattedReport):
UPDATE A SET underInvestigation = Amount FROM #ReportData B
INNER JOIN #FormattedReport A ON B.CaseType LIKE CONCAT('%', A.caseType, '%')
WHERE B.StatusType = 'Under Investigation'
UPDATE A SET closed = Amount FROM #ReportData B
INNER JOIN #FormattedReport A ON B.CaseType LIKE CONCAT('%', A.caseType, '%')
WHERE B.StatusType = 'Closed'
...
REQUESTED Update Statement: Would like to have ONE update statement knowing which column to update when "#ReportData.statusType" is the same as a "#FormattedData" column's name. For my "other" column, I'll just do that one manually using a NOT IN.
Assuming I understand the question, I think you can use conditional aggregation for this:
;WITH CTE AS
(
SELECT CaseType
,SUM(CASE WHEN StatusType = 'Under Investigation' THEN Amount ELSE 0 END) As underInvestigation
,SUM(CASE WHEN StatusType = 'Closed' THEN Amount ELSE 0 END) As closed
-- ... More of the same
FROM #ReportData
GROUP BY CaseType
)
UPDATE A
SET underInvestigation = B.underInvestigation
,closed = b.closed
-- more of the same
FROM #FormattedReport A
INNER JOIN CTE B
ON B.CaseType LIKE CONCAT('%', A.caseType, '%')

T-SQL how to join with one column a string and one an integer

How to join with one column a string and one an integer?
--PEOPLE_ID 000092437, PersonID 92437
select PC.PEOPLE_ID, Idn.PersonId,'Home Row 1', PC.Phone1 from #NextIdentityID Idn INNER JOIN PEOPLECHANGES PC on Idn.People_ID = PC.People_ID --PEOPLE_ID 000092437, PersonID 92437 one is varchar, one is integer
union all select PC.PEOPLE_ID, Idn.PersonId,'Office Row 2', PC.Phone2 from #NextIdentityID Idn INNER JOIN PEOPLECHANGES PC on Idn.People_ID = PC.People_ID
union all select PC.PEOPLE_ID, Idn.PersonId,'Cell Row 3', PC.Phone3 from #NextIdentityID Idn INNER JOIN PEOPLECHANGES PC on Idn.People_ID = PC.People_ID
To make sure your varchar() data doesn't raise any errors you should check to see if it can be converted into an integer. One way to do this is with a case statement in the where clause. If it is not convertible then your join won't work - but at least your query can still run with out error.
This example shows how you can avoid potential errors.
create table #tempa(id int, descr varchar(50));
create table #tempb(id varchar(10), descr varchar(50));
insert into #tempa(id,descr) values (1234,'Body getta body getta');
insert into #tempb(id,descr) values ('001234','sis boom ba - rah rah rah');
insert into #tempa(id,descr) values (5678,'Weagle Weagle War Damn Eagle');
insert into #tempb(id,descr) values ('0005678','Kickem in the butt Big blue');
insert into #tempa(id,descr) values (9012,'this wont have a match');
insert into #tempb(id,descr) values ('x0912','sis boom ba');
Select a.id as a_id, b.id as b_id
,a.descr as a_descr, b.descr as b_descr
from #tempa a
left join #tempb b
on a.id = case when isnumeric(b.id) = 1 then cast(b.id as int) else 0 end
-- this one will raise an error
Select a.id as a_id, b.id as b_id
,a.descr as a_descr, b.descr as b_descr
from #tempa a
left join #tempb b
on a.id = b.id
drop table #tempa;
drop table #tempb;
If you convert the one with leading zeros to an integer you will get equal values:
SELECT CONVERT(INT, '000092437') = 92437
However, this assumes that all of your varchar column can be convert to int.
If that's not the case then you have to write a function to go the other way and add leading zeros.

PostgreSQL 9.3: Split one column into multiple

I want to split one column that is colb in the given below example into two columns
like column1 and column2.
I have a table with two columns:
Example:
create table t3
(
cola varchar,
colb varchar
);
Insertion:
insert into t3 values('D1','2021to123'),
('D2','112to24201'),
('D3','51to201');
I want to split the colb values into two columns like the following expected result:
Expected Result:
cola column1 column2
---------------------------------
D1 2021 123
D2 112 24201
D3 51 201
select cola
,split_part(colb, 'to', 1) col1
,split_part(colb, 'to', 2) col2
from t3
Quoted from the PostgreSQL Documentation:
split_part(string text, delimiter text, field int)
Split string on delimiter and return the given field (counting from
one)

T-SQL: Selecting column from an alternate table when null

I have the following table, TableA, with data:
ID ColA
0 10
1 null
2 20
I have another table, TableB, with the following data.
ID ColB ColC
1 30 80
1 40 70
3 50 100
I need to select rows in TableA but when ColA in the row is null, I want to retrieve the value of ColB in TableB (if one exists) and use it in place of ColA. If no value in ColB exists, then the value of ColA in the result should be null. The join is done on TableA.ID and TableB.ID. TableB can have multiple rows where the ID column repeats. TableB.ID and TableB.ColC together make a row unique. So my result should look like this if ColC is limited to the value of 70:
ID ColA
0 10
1 40
2 20
Not sure how to do this. Thanks for your help!
select a.ID, COALESCE(a.ColA, b.ColB) as 'ColA'
from TableA a
left join TableB b on a.ID = b.ID and b.ColC = 70
This seems to do what you want if I have correctly interpreted your question:
SELECT a.ID,
ISNULL(a.ColA, b.ColB) ColA
FROM TableA a
LEFT JOIN
TableB b
ON a.ID = b.ID
AND b.ColC = 70
I have literally "limited to the value of 70" in ColC as you stated.
sounds like you're looking for a case statement. try case when TableA.Value is null then TableB.Value end
SQL Case Statements