Converting a number value in a field to a word - sql

I have a SQL query that I'm building and need to convert a number to a word.
The field is titled Type and the values are 1 or 2. I need to convert the 1 to display as Problem and the 2 to display as Resolution.
How would i go about doing this. I built this as an expression in SQL data tools, but we are going in a different direction and need to add it to the query instead and display the report another way.
Thanks!

I'd recommend you have a second table with your ID/Name combination as a lookup and do a JOIN.
That way, as new types come in, you only have to change the name, and not the code.
Although, the syntax would be
CASE WHEN Type = 1 THEN 'Problem'
WHEN Type = 2 THEN 'Resolution' END

You've essentially built the first portion of a normalized database, you've just haven't completed the second portion. The numbers: 1 and 2, can be foreign keys to a second data table that links to the second table's unique auto-incremented ID field:
+-------+ +----+-------------+
| Type | | ID | Description |
+-------+ +----+-------------+
| 1 | | 1 | Problem |
| 2 | | 2 | Resolution |
| 2 | +----+-------------+
| 1 |
+-------+
Which this schema, you can then query the data like such:
SELECT `table2`.`description`
FROM `table2`
INNER JOIN `table1`
ON `table1`.`type` = `table2`.`id`
WHERE `table1`.`type` = 1
Fiddle: Live Demo
What this does is it allows you to add more IDs and Descriptions to your second data table without having to rewrite a bunch of code.

Try below option, it will work with 2 types only (as in question):
Declare #Type int = 1
select
case #Type when 1 then 'Problem'
else 'Resolution'
end as Result
set #Type = 2
select
case #Type when 1 then 'Problem'
else 'Resolution'
end as Result

Related

SQL Query to replace multiple values in template from many-to-many table

I want to translate a template in an sql query. Lets assume there are the following fourtables: state, stateProperty, state_stateproperty and translation:
state_stateproperty
|---------------------|--------------------|
| state_id | stateproperties_id |
|---------------------|--------------------|
| 1 | 2 |
|---------------------|--------------------|
| 1 | 3 |
|---------------------|--------------------|
stateproperty
|---------------------|------------------|
| id | key | value |
|------|--------------|------------------|
| 2 | ${firstName} | John |
|------|--------------|------------------|
| 3 | ${lastName} | Doe |
|------|--------------|------------------|
state
|---------------------|
| id | template |
|------|--------------|
| 1 | template |
|------|--------------|
translation
|------------|--------------|---------------------------------|
| language | messageId | value |
|------------|--------------|---------------------------------|
| en | template | ${lastName}, ${firstName} alarm |
|------------|--------------|---------------------------------|
The aim is to get a new entity named translatedstate that includes the translated template of the state. In this example the translated template would look like: "Doe, John alarm". How can you join a many to many table in native sql and translate the template of the state with the values of its related state properties?
To be honest I would create a little function where I would loop through your state_property and cumulative replace the found wildcard string with its text.
But I had some fun to solve it in a query. I am not sure if it matches all special cases but for your example it works:
demo:db<>fiddle
SELECT
string_agg( -- 8
regexp_replace(split_key, '^.*\}', value), -- 7
'' ORDER BY row_number
)
FROM (
SELECT
s.id,
sp.value,
substring(key, 3) as s_key, -- 5
split_table.*
FROM translation t
JOIN statechange sc ON t.messageid = sc.completemessagetemplateid -- 1
JOIN state s ON s.id = sc.state_id
JOIN state_stateproperty ssp ON s.id = ssp.state_id
JOIN stateproperty sp ON ssp.stateproperties_id = sp.id
JOIN translation stnme ON s.nameid = stnme.messageid
CROSS JOIN
regexp_split_to_table( -- 3
-- 2
replace(t.messagetranslation, '${state}', stnme.messagetranslation),
'\$\{'
) WITH ORDINALITY as split_table(split_key, row_number) -- 4
WHERE t.language = 'en'
) s
WHERE position(s_key in split_key) = 0 and split_key != '' -- 6
GROUP BY id -- 8
Simple join the tables together (for next time you could simplify your example a little bit so that we don't have to create these different table. I am sure you know how to join)
Hardly replace the ${state} variable with the state nameid
This splits the template string every time a ${ string is found. So it creates a new row which begins a certain wildcard. Note that ${firstName} would become firstName} because the string delimiter is being deleted.
Adding a row count to get a criteria how the rows are ordered when I aggregate them later (8). WITH ORDINALITY only works as part of the FROM clause so the whole function it has been added here with a join.
Because of (3) I strip the ${ part from the keys as well. So it can be better parsed and compared later (in 6)
Because (3) creates too much rows (cross join) I want only these where the key is the first wildcard of my split string. All others are wrong.
Now I replace the wildcard with this key
Because we have only one wildcard per row we need to merge them together into one string again (grouped by state_id). The achieve the right order, we are using the row number from (5)

SQL Statement - Select from two tables, create column if secondary table has related record

I'm posting here because I have not been able to find what I'm looking for, or even the correct keywords to search on. If there are better answers that I was unable to find, please feel free to point me in that direction.
However I have two tables which Table 1 is the primary table, and I need to SELECT all records out of it and add an additional column in the SELECT that returns if any related records in Table 2.
I have boiled the problem down to the following and any help would be much appreciated.
Table 1 has a many relationship to Table 2
SELECT must return all rows from Table 1
SELECT must have an additional column (preferably a BOOLEAN/INTEGER) column that represents if there are any related records in Table 2.
SELECT must work in both Access and SQL Server
TABLE 1
--------
GUID1 | DATA FIELD | DATA FIELD
GUID2 | DATA FIELD | DATA FIELD
GUID3 | DATA FIELD | DATA FIELD
TABLE 2
--------
GUID1 | TABLE 1 GUID | DATA FIELD | DATA FIELD
GUID2 | TABLE 1 GUID | DATA FIELD | DATA FIELD
GUID3 | TABLE 2 GUID | DATA FIELD | DATA FIELD
GUID4 | TABLE 2 GUID | DATA FIELD | DATA FIELD
SELECTED TABLE ( 1 JOINED ON TABLE 2 )
--------
GUID1 | DATA FIELD | DATA FIELD | 1 (EXISTS IN TABLE 2)
GUID2 | DATA FIELD | DATA FIELD | 1 (EXISTS IN TABLE 2)
GUID3 | DATA FIELD | DATA FIELD | 0 (DOES NOT EXISTS IN TABLE 2)
You can use a LEFT OUTER JOIN with a case statement to check if the data in the second table is null. Here is an example:
SELECT First.*,
CASE
WHEN Second.DATA3 IS NULL
THEN 0
ELSE 1
END
FROM First
LEFT OUTER JOIN Second ON First.GUID1 = Second.GUID1
SQL Fiddle: http://sqlfiddle.com/#!6/ab17a/1

SQL join two tables using value from one as column name for other

I'm a bit stumped on a query I need to write for work. I have the following two tables:
|===============Patterns==============|
|type | bucket_id | description |
|-----------------------|-------------|
|pattern a | 1 | Email |
|pattern b | 2 | Phone |
|==========Results============|
|id | buc_1 | buc_2 |
|-----------------------------|
|123 | pass | |
|124 | pass |fail |
In the results table, I can see that entity 124 failed a validation check in buc_2. Looking at the patterns table, I can see bucket 2 belongs to pattern b (bucket_id corresponds to the column name in the results table), so entity 124 failed phone validation. But how do I write a query that joins these two tables on the value of one of the columns? Limitations to how this query is going to be called will most likely prevent me from using any cursors.
Some crude solutions:
SELECT "id", "description" FROM
Results JOIN Patterns
ON "buc_1" = 'fail' AND "bucket_id" = 1
union all
SELECT "id", "description" FROM
Results JOIN Patterns
ON "buc_2" = 'fail' AND "bucket_id" = 2
Or, with a very probably better execution plan:
SELECT "id", "description" FROM
Results JOIN Patterns
ON "buc_1" = 'fail' AND "bucket_id" = 1
OR "buc_2" = 'fail' AND "bucket_id" = 2;
This will report all failure descriptions for each id having a fail case in bucket 1 or 2.
See http://sqlfiddle.com/#!4/a3eae/8 for a live example
That being said, the right solution would be probably to change your schema to something more manageable. Say by using an association table to store each failed test -- as you have in fact here a many to many relationship.
An other approach if you are using Oracle ≥ 11g, would be to use the UNPIVOT operation. This will translate columns to rows at query execution:
select * from Results
unpivot ("result" for "bucket_id" in ("buc_1" as 1, "buc_2" as 2))
join Patterns
using("bucket_id")
where "result" = 'fail';
Unfortunately, you still have to hard-code the various column names.
See http://sqlfiddle.com/#!4/a3eae/17
It looks to me that what you really want to know is the description(in your example Phone) of a Pattern entry given the condition that the bucket failed. Regardless of the specific example you have you want a solution that fulfills that condition, not just your particular example.
I agree with the comment above. Your bucket entries should be tuples(rows) and not arguments, and also you should share the ids on each table so you can actually join them. For example, Consider adding a bucket column and index their number then just add ONE result column to store the state. Like this:
|===============Patterns==============|
|type | bucket_id | description |
|-----------------------|-------------|
|pattern a | 1 | Email |
|pattern b | 2 | Phone |
|==========Results====================|
|entity_id | bucket_id |status |
|-------------------------------------|
|123 | 1 |pass |
|124 | 1 |pass |
|123 | 2 | |
|124 | 2 |fail |
1.-Use an Inner Join: http://www.w3schools.com/sql/sql_join_inner.asp and the WHERE clause to filter only those buckets that failed:
2.-Would this example help?
SELECT Patterns.type, Patterns.description, Results.entity_id,Results.status
INNER JOIN Results
ON
Patterns.bucket_id=Results.bucket_id
WHERE
Results.status=fail
Lastly, I would also add a primary_key column to each table to make sure indexing is faster for each unique combination.
Thanks!

Language fallback with database content in OpenCart

I've just (6 months+) started learning all the web languages, mostly within OpenCart's framework. Right now I'm trying to get language fallback to work with database content.
The objective is to check for an empty field in id.title and if so choose the default language_id=1.
The language_id comes from a GET request invoked by the frontend user.
The table description looks like this:
------------------------------------------------------
| information_id | language_id | title | description |
------------------------------------------------------
| 3 | 1 | policy | policy desc |
------------------------------------------------------
| 4 | 1 | about | about desc |
------------------------------------------------------
| 4 | 2 | | |
------------------------------------------------------
| 5 | 1 | terms | terms desc |
------------------------------------------------------
| 6 | 1 | comp | comp desc |
------------------------------------------------------
As you can see language_id=2 has no title nor description (inserted by sql, not oc's admin). In this case I want to get the row with the default language=1.
I've tried using CASE but the results are always empty. The problem I can't find a solution for this is to check the title field next to the requested language_id.
I've also tried to first check the field before doing a SELECT, but no success.
SELECT DISTINCT *
FROM information_description id
WHERE id.information_id = '4'
AND id.language_id = (CASE WHEN id.title = '' THEN '1' ELSE '2' END);
Any help would be appreciated.
Here You have two options. Either do this by subselects or once per save/update walk through all the information descriptions and update the missing languages with the texts from the default ones.
The first solution could be:
SELECT id.information_id, id.language_id, id.description,
CASE WHEN id.title IS NOT NULL /* or CASE WHEN id.title <> '' - depending on the real value in DB when it's empty */
THEN id.title
ELSE (SELECT title FROM information_description WHERE language_id = 1)
AS title
FROM information_description id
WHERE id.language_id = 2
I would call such query only in the case when the language ID differs from the default one. Since this may look like working solution I don't like it simply because it increases the DB effort.
Instead of this I recommend to simply update Your missing data in similar way (this could be done maybe only once per life and you are done):
UPDATE information_description id SET
id.title = (SELECT title FROM information_description WHERE language_id = 1 AND information_id = id.information_id)
WHERE id.language_id <> 1
AND id.title IS NULL
for title and
UPDATE information_description id SET
id.description = (SELECT description FROM information_description WHERE language_id = 1 AND information_id = id.information_id)
WHERE id.language_id <> 1
AND id.description IS NULL
for description fields...

SQL JOIN on Dynamic Column based on Variable

I have an image summary table [summary] that will serve as a reporting table in the near future. There is a reference table [views] and a third table that the image team populates [TeamImage]. The summary table has 1 row per part number (table has distinct part numbers) and many columns of image views (TOP, BOT, FRO, BAC, etc.). The [views] table lists each of these views with an id field, which is an IDENTITY field. The [TeamImage] table contains part numbers and views (part number field is not unique as the part numbers will be listed multiple times as they have image views).
Example:
TABLE [summary]
Part_Number | TOP | BOT | FRO | BAC |
12345 | | | | |
67890 | | | | |
TABLE [views]
id | View |
1 | TOP |
2 | BOT |
3 | FRO |
4 | BAC |
TABLE [TeamImage]
PartNum | View |
12345 | TOP |
12345 | BOT |
12345 | FRO |
12345 | BAC |
67890 | FRO |
67890 | BAC |
Here's what I need in the end:
TABLE [summary]
Part_Number | TOP | BOT | FRO | BAC |
12345 | 1 | 1 | 1 | 1 |
67890 | | | 1 | 1 |
I could run several update queries but I have 27 views and about 2 million part numbers. I was hoping I could run something like below, even though I know I cannot use a variable as the column name:
DECLARE #id int = (SELECT max(id) FROM [views]), #ViewType nvarchar(3);
WHILE #id IS NOT NULL
BEGIN
SELECT #ViewType = (SELECT [View] FROM [views] WHERE id = #id);
UPDATE a
SET a.[#ViewType] = '1'
FROM [summary] a
INNER JOIN [TeamImage] b
AND a.[Part_Number] = b.[PartNum]
WHERE b.[View] = #ViewType;
SELECT #id = max(id) FROM [views] WHERE id < #id;
END;
Basically, I was hoping to use a variable to grab the different views from the [views] table (id = 27 down to id=1...could have counted up but doesn't matter) and populate the corresponding field in the [summary] table.
I know the SET a.[#ViewType] = '1' won't work, and a colleague of mine mentioned using VB but didn't know if that really was the most efficient option. I understand that I could use a PIVOT on the [TeamImage] table, but I'm not sure that will allow me to update my [summary] table (which has many more fields in it than just the image views). It still seems I need something that will effectively loop through update queries. I could write 4 update queries, one for each view (although my real table has 27 views), but I need something more dynamic in case we add views in the future.
To create your final summary, you can do via a simple pivot, yet this is fixed to the few codes you've done... but I know SQL does have a PIVOT command, but not directly familiar enough with it.
select
TA.PartNum,
max( case when TA.TeamImage = 'TOP' then '1' else ' ' end ) as TOPview,
max( case when TA.TeamImage = 'BOT' then '1' else ' ' end ) as BOTview,
max( case when TA.TeamImage = 'FRO' then '1' else ' ' end ) as FROview,
max( case when TA.TeamImage = 'BAC' then '1' else ' ' end ) as BACview
from
TeamImage TA
group by
TA.PartNum
Obviously simple to expand, but you can also look into the "PIVOT" syntax
I asked the question a little better here: SQL output as variable in VB.net and was able to receive an answer that worked for what I was looking for. I appreciate DRapp providing a solution through PIVOT, but I think the VB way will be easier for me moving forward. In short, using VB with ExecuteScalar and ExecuteNonQuery, I was able to re-write my query using the variables I had above.