SQL Expression Assistance - sql

I am pulling data from using Telerik Standalone Reporting Application. I have a Table called "Product" one of the columns is called "ProductStatus". ProductStatus is an int value ranging from 1-12. Breakdown below:
"1"=Active
"2"=Retired
"3"=Processing
"5"=Archived
"6"=Active-Empty
"7"=Available
"8"=Resigned
"9"=Terminated
"10"=Legal Freeze
"11"=Admin Hold
"12"=Reserved
My question is: How can I write an Expression that will Look at "ProductStatus" and If = to 1 Then Return "Active" Or If = to 2 Then Return "Retired" etc.

You have 2 ways to do that
use CASE and code the translation table in the request
SELECT CASE WHEN 1 THEN 'Active' ... END FROM ...;
put the translation table in a database table and use a join :
CREATE TABLE product_status(id INTEGER, status VARCHAR(32));
INSERT INTO product_status(id, status) VALUES(1, 'Active');
...
SELECT ps.status, ... FROM product_status, ... WHERE product_status.id = ..., ... ;

You can create a table with all status texts like this:
CREATE TABLE statusText
([id] int, [text] varchar(12))
;
INSERT INTO statusText
([id], [text])
VALUES
(1, 'Active'),
(2, 'Retired'),
(3, 'Processing'),
(5, 'Archived'),
(6, 'Active-Empty'),
(7, 'Available'),
(8, 'Resigned'),
(9, 'Terminated'),
(10, 'Legal Freeze'),
(11, 'Admin Hold'),
(12, 'Reserved')
;
And then join Products table like this:
SELECT a.*, b.Text
FROM Products a INNER JOIN statusText b
ON a.ProductStatus=b.id

Related

sql query to join two tables and a boolean flag to indicate whether it contains any words from third table

I have 3 tables with the following schema
create table main (
main_id int PRIMARY KEY,
secondary_id int NOT NULL
);
create table secondary (
secondary_id int NOT NULL,
tags varchar(100)
);
create table bad_words (
words varchar(100) NOT NULL
);
insert into main values (1, 1001);
insert into main values (2, 1002);
insert into main values (3, 1003);
insert into main values (4, 1004);
insert into secondary values (1001, 'good word');
insert into secondary values (1002, 'bad word');
insert into secondary values (1002, 'good word');
insert into secondary values (1002, 'other word');
insert into secondary values (1003, 'ugly');
insert into secondary values (1003, 'bad word');
insert into secondary values (1004, 'pleasant');
insert into secondary values (1004, 'nice');
insert into bad_words values ('bad word');
insert into bad_words values ('ugly');
insert into bad_words values ('worst');
expected output
----------------
1, 1000, good word, 0 (boolean flag indicating whether the tags contain any one of the words from the bad_words table)
2, 1001, bad word,good word,other word , 1
3, 1002, ugly,bad word, 1
4, 1003, pleasant,nice, 0
I am trying to use case to select 1 or 0 for the last column and use a join to join the main and secondary table, but getting confused and stuck. Can someone please help me with a query ? These tables are stored in redshift and i want query compatible with redshift.
you can use the above schema to try your query in sqlfiddle
EDIT: I have updated the schema and expected output now by removing the PRIMARY KEY in secondary table so that easier to join with the bad_words table.
You can use EXISTS and a regex comparison with \m and \M (markers for beginning and end of a word, respectively):
with
main(main_id, secondary_id) as (values (1, 1000), (2, 1001), (3, 1002), (4, 1003)),
secondary(secondary_id, tags) as (values (1000, 'very good words'), (1001, 'good and bad words'), (1002, 'ugly'),(1003, 'pleasant')),
bad_words(words) as (values ('bad'), ('ugly'), ('worst'))
select *, exists (select 1 from bad_words where s.tags ~* ('\m'||words||'\M'))::int as flag
from main m
join secondary s using (secondary_id)
select main_id, a.secondary_id, tags, case when c.words is not null then 1 else 0 end
from main a
join secondary b on b.secondary_id = a.secondary_id
left outer join bad_words c on c.words like b.tags
SELECT m.main_id, m.secondary_id, t.tags, t.is_bad_word
FROM srini.main m
JOIN (
SELECT st.secondary_id, st.tags, exists (select 1 from srini.bad_words b where st.tags like '%'+b.words+'%') is_bad_word
FROM
( SELECT secondary_id, LISTAGG(tags, ',') as tags
FROM srini.secondary
GROUP BY secondary_id ) st
) t on t.secondary_id = m.secondary_id;
This worked for me in redshift and produced the following output with the above mentioned schema.
1 1001 good word false
3 1003 ugly,bad word true
2 1002 good word,other word,bad word true
4 1004 pleasant,nice false

How to insert multiple row values into SQL

I have the following 3 tables:
CREATE TABLE Tests (
Test_ID INT,
TestName VARCHAR(50));
INSERT INTO Tests VALUES (1, 'SQL Test');
INSERT INTO Tests VALUES (2, 'C# Test');
INSERT INTO Tests VALUES (3, 'Java Test');
CREATE TABLE Users (
[User_ID] INT,
UserName VARCHAR(50));
INSERT INTO Users VALUES (1, 'Joe');
INSERT INTO Users VALUES (2, 'Jack');
INSERT INTO Users VALUES (3, 'Jane');
CREATE TABLE UserTests (
ID INT,
[User_ID] INT,
Test_ID INT,
Completed INT);
INSERT INTO UserTests VALUES (1, 1, 1, 0);
INSERT INTO UserTests VALUES (2, 1, 2, 1);
INSERT INTO UserTests VALUES (3, 1, 3, 1);
INSERT INTO UserTests VALUES (4, 2, 1, 0);
INSERT INTO UserTests VALUES (5, 2, 2, 0);
INSERT INTO UserTests VALUES (6, 2, 3, 0);
INSERT INTO UserTests VALUES (7, 3, 1, 1);
INSERT INTO UserTests VALUES (8, 3, 2, 1);
INSERT INTO UserTests VALUES (9, 3, 3, 1);
I would like to create some rule/trigger so that when a new user gets added to the Users table, an entry for each Test and that user's Id will get added to the UserTests table.
Something like this if the new user ID is 5:
INSERT dbo.UserTest
(USER_ID, TEST_ID, Completed)
VALUES
(5, SELECT TEST_ID FROM Tests, 0)
That syntax is of course wrong but to give an idea of what I expect to happen.
So I expect that statement to add these values to the UserTests table:
User ID| Test ID| Completed
5 | 1 | 0
5 | 2 | 0
5 | 3 | 0
You can use after trigger for user table.
Create Trigger tr_user on Users
After Insert
AS Begin
INSERT UserTest(USER_ID, TEST_ID, Completed)
Select I.USER_ID, t.TEST_ID, 0
From Inserted I, Tests t
END
Here's a SQL Fiddle that finds missing records and inserts them.
SQL Fiddle
The SELECT:
select u.user_id, t.test_id, 0 as Completed
from users u
cross join tests t
where not exists (
select 1
from usertests ut
where ut.user_id = u.user_id and ut.test_id = t.test_id)
Adding insert into UserTests (User_Id, Test_Id, Completed) before the select will insert these records.
You can add a user id on to the where clause to do it for a single user if required. It is re-runnable so it won't re-insert test ids for a user that already has them, but will add new ones if new tests are introduced.

Is it possible to Left outer join normal table with temp table?

I create SQL server query and have normal table with records and in the other hand have a temp table with record and this table not empty and all fields doesn't have any conflict to
join
is possible to join this two different type table?
SELECT NormalTable.Entityname FROM NormalTable LEFT JOIN
#Temp tmp ON tmp.joinID = NormalTable.joinID
is possible to join this two different type table? (normal and temporary)
Yes it is possible to join different type of table (permanent and temporary tables). There is no different syntax to join these tables.
E.g.
Permanent table:
CREATE TABLE NormalTable
([plateno] varchar(1), [JoinID] int)
;
INSERT INTO NormalTable
([plateno], [JoinID])
VALUES
('A', 1),
('B', 2),
('C', 2),
('A', 3),
('B', 2),
('A', 4),
('A', 1)
;
Temporary table:
CREATE TABLE #Temp
([id] int, [date] date, [score] int)
;
INSERT INTO #Temp
([id], [date], [score])
VALUES
(1, '2013-04-13', 100),
(2, '2013-04-14', 92),
(3, '2013-04-15', 33)
;
Join both tables:
SELECT N.* FROM NormalTable N
LEFT JOIN #Temp T ON N.JoinID = T.ID
Have a look at this SQLFiddle

Check if matching child records exist before saving parent records

We basically have a set of child records in which we will use to create a new parent/child record(s) but need to first verify that a parent record doesn't already exist containing the same child records. Here are the details:
We have 3 tables, one is basically a linking table between the parent and children records.
Table A (parent table)
Id
Name
Desc
Table B (linking table between tables A and C)
Id
TableAId
TableCId
Table C (child table)
Id
StartPosition
EndPosition
Percentage
So with that structure, here is an example of a complete record, the parent table it one-to-many relation with child table:
Table A
(1, 'Sample', 'N/A')
Table B
(1, 1, 1)
(2, 1, 2)
(3, 1, 3)
Table C
(1, 1, 3, 0.50)
(2, 4, 5, 0.30)
(3, 6, 9, 0.20)
So we then pass in an xml string which we parse and throw into a temp table. The contents of the temp table are that of Table C, without the specific Id.
Then before we save any new records, we need to check if there is an existing Table A record which has both the same number of child records and that those child records match the 3 columns in our temp table (no ID match possible).
Hopefully this is explained well enough, I have done many searches and can't find anything specific to this issue.
What you're looking for is called a relational division. The article "Divided We Stand: The SQL of Relational Division" provides a nice summary of various techniques for using SQL to perform a relational division. For your case, you want the technique listed under "Exact Division":
CREATE TABLE tableA (
Id int PRIMARY KEY,
Name varchar(25),
[Desc] varchar(255)
);
INSERT INTO tableA
(Id, Name, [Desc])
VALUES
(1, 'Sample 1', 'Should match the XML'),
(2, 'Sample 2', 'Partial match (should be excluded)'),
(3, 'Sample 3', 'Has extra matches (should be excluded)');
GO
CREATE TABLE tableB (
Id int PRIMARY KEY,
TableAId int,
TableCId int
);
INSERT INTO tableB
(Id, TableAId, TableCId)
VALUES
(1, 1, 1),
(2, 1, 2),
(3, 1, 3),
(4, 2, 1),
(5, 2, 2),
(6, 3, 1),
(7, 3, 2),
(8, 3, 3),
(9, 3, 4);
GO
CREATE TABLE tableC (
Id int PRIMARY KEY,
StartPosition int,
EndPosition int,
Percentage decimal(3,2)
);
INSERT INTO tableC
(Id, StartPosition, EndPosition, Percentage)
VALUES
(1, 1, 3, 0.50),
(2, 4, 5, 0.30),
(3, 6, 9, 0.20),
(4, 10, 12, 0.10);
GO
-- this represents the temp table holding the XML data
-- we want to match Sample 1
CREATE TABLE xmlData (
StartPosition int,
EndPosition int,
Percentage decimal(3,2)
);
INSERT INTO xmlData
(StartPosition, EndPosition, Percentage)
VALUES
(1, 3, 0.50),
(4, 5, 0.30),
(6, 9, 0.20);
GO
SELECT
b.TableAId
FROM
tableB AS b
INNER JOIN
tableC AS c
ON
b.TableCId = c.Id
LEFT OUTER JOIN
xmlData AS x
ON
c.StartPosition = x.StartPosition AND
c.EndPosition = x.EndPosition AND
c.Percentage = x.Percentage
GROUP BY
b.TableAId
HAVING
COUNT(c.Id) = (SELECT COUNT(*) FROM xmlData) AND
COUNT(x.StartPosition) = (SELECT COUNT(*) FROM xmlData);
GO
DROP TABLE xmlData;
DROP TABLE tableC;
DROP TABLE tableB;
DROP TABLE tableA;
GO

Oracle PIVOT, twice?

I have been trying to move away from using DECODE to pivot rows in Oracle 11g, where there is a handy PIVOT function. But I may have found a limitation:
I'm trying to return 2 columns for each value in the base table. Something like:
SELECT somethingId, splitId1, splitName1, splitId2, splitName2
FROM (SELECT somethingId, splitId
FROM SOMETHING JOIN SPLIT ON ... )
PIVOT ( MAX(splitId) FOR displayOrder IN (1 AS splitId1, 2 AS splitId2),
MAX(splitName) FOR displayOrder IN (1 AS splitName1, 2 as splitName2)
)
I can do this with DECODE, but I can't wrestle the syntax to let me do it with PIVOT. Is this even possible? Seems like it wouldn't be too hard for the function to handle.
Edit: is StackOverflow maybe not the right Overflow for SQL questions?
Edit: anyone out there?
From oracle-developer.net it would appear that it can be done like this:
SELECT somethingId, splitId1, splitName1, splitId2, splitName2
FROM (SELECT somethingId, splitId
FROM SOMETHING JOIN SPLIT ON ... )
PIVOT ( MAX(splitId) ,
MAX(splitName)
FOR displayOrder IN (1 AS splitName1, 2 as splitName2)
)
I'm not sure from what you provided what the data looks or what exactly you would like. Perhaps if you posted the decode version of the query that returns the data you are looking for and/or the definition for the source data, we could better answer your question. Something like this would be helpful:
create table something (somethingId Number(3), displayOrder Number(3)
, splitID Number(3));
insert into something values (1, 1, 10);
insert into something values (2, 1, 11);
insert into something values (3, 1, 12);
insert into something values (4, 1, 13);
insert into something values (5, 2, 14);
insert into something values (6, 2, 15);
insert into something values (7, 2, 16);
create table split (SplitID Number(3), SplitName Varchar2(30));
insert into split values (10, 'Bob');
insert into split values (11, 'Carrie');
insert into split values (12, 'Alice');
insert into split values (13, 'Timothy');
insert into split values (14, 'Sue');
insert into split values (15, 'Peter');
insert into split values (16, 'Adam');
SELECT *
FROM (
SELECT somethingID, displayOrder, so.SplitID, sp.splitname
FROM SOMETHING so JOIN SPLIT sp ON so.splitID = sp.SplitID
)
PIVOT ( MAX(splitId) id, MAX(splitName) name
FOR (displayOrder, displayOrder) IN ((1, 1) AS split, (2, 2) as splitname)
);