Rename column after PIVOT - sql

I am newbie in SQL so apologize if the question does not make sense.
I have a table that looks like (I am on google colab)
CREATE TEMP TABLE test (
name STRING,
subjectId INT,
score INT
);
INSERT INTO test (name, subjectId, score) VALUES ('David', 123, 90);
INSERT INTO test (name, subjectId, score) VALUES ('David', 10, 80);
INSERT INTO test (name, subjectId, score) VALUES ('Ana', 34, 75);
INSERT INTO test (name, subjectId, score) VALUES ('Ryan', 123, 100);
There is a column called subjectId. I would like to apply the PIVOT operator on. I do not know what are the distinct values in this column. So I first create a string to record the distinct value of this column:
DECLARE subjects STRING;
SET subjects = (
SELECT
CONCAT('(', STRING_AGG(DISTINCT CAST(subjectId AS STRING), ', '), ')'),
FROM
test
);
Now I can proceed to apply the PIVOT operation:
EXECUTE IMMEDIATE format("""
SELECT
*
FROM (
SELECT name, subjectId, score FROM test
) AS T
PIVOT
(
max(score) for subjectId in %s
) AS P
""", subjects);
This give me the following table:
Now you can see the columns are named according to the distinct values of the subjectId column. What I would like to do is to rename those columns to something like subject1, subject2, subject3, etc., and I do not care about the order. How can I do that?

Related

Finding trouble in generating the list of all Students who belongs to the major named as “CS” but not to major named as “EE”

S_id int Primary Key,
S_name varchar(100),
Gpa float ,
Size_hs int
)
Create table Apply (
s_id int ,
C_name varchar(100),
Major varchar(10),
Decision varchar(2)
)
insert into Students values (123,'Amy',3.9,1000)
insert into Students values (234,'Bob',3.6,1500)
insert into Students values (345,'Craig',3.5,500)
insert into Students values (456,'Doug',3.9,1000)
insert into Students values (567,'Edward',2.9,2000)
insert into Students values (678,'Fay',3.8,200)
insert into Students values (789,'Gray',3.4,800)
insert into Students values (987,'Helen',3.7,800)
insert into Students values (876,'Irene',3.9,400)
insert into Students values (765,'Jay',2.9,1500)
insert into Students values (654,'Amy',3.9,1000)
insert into Students values (543,'Craig',3.4,2000)
insert into Apply values (123,'NJIT','CS','Y')
insert into Apply values (123,'NJIT','EE','N')
insert into Apply values (123,'Stoony Brook','CS','Y')
insert into Apply values (123,'Cornell','EE','Y')
insert into Apply values (234,'Stoony Brook','Bio','N')
insert into Apply values (345,'WPI','Bio-Eng','Y')
insert into Apply values (345,'Cornell','Bio-Eng','N')
insert into Apply values (345,'Cornell','CS','Y')
insert into Apply values (345,'Cornell','EE','N')
insert into Apply values (678,'NJIT','Hist','Y')
insert into Apply values (987,'NJIT','CS','Y')
insert into Apply values (987,'Stoony Brook','CS','Y')
insert into Apply values (876,'NJIT','Bio','N')
insert into Apply values (876,'WPI','Marine-Bio','Y')
insert into Apply values (876,'WPI','Hist','N')
insert into Apply values (765,'NJIT','Hist','Y')
insert into Apply values (765,'Cornell','Hist','N')
insert into Apply values (765,'Cornell','Psych','Y')
insert into Apply values (543,'WPI','CS','N')
Create table Students(
S_id int Primary Key,
S_name varchar(100),
Gpa float ,
Size_hs int
)
Create table Apply (
s_id int ,
C_name varchar(100),
Major varchar(10),
Decision varchar(2)
)
insert into Students values (123,'Amy',3.9,1000)
insert into Students values (234,'Bob',3.6,1500)
insert into Students values (345,'Craig',3.5,500)
insert into Students values (456,'Doug',3.9,1000)
insert into Students values (567,'Edward',2.9,2000)
insert into Students values (678,'Fay',3.8,200)
insert into Students values (789,'Gray',3.4,800)
insert into Students values (987,'Helen',3.7,800)
insert into Students values (876,'Irene',3.9,400)
insert into Students values (765,'Jay',2.9,1500)
insert into Students values (654,'Amy',3.9,1000)
insert into Students values (543,'Craig',3.4,2000)
insert into Apply values (123,'NJIT','CS','Y')
insert into Apply values (123,'NJIT','EE','N')
insert into Apply values (123,'Stoony Brook','CS','Y')
insert into Apply values (123,'Cornell','EE','Y')
insert into Apply values (234,'Stoony Brook','Bio','N')
insert into Apply values (345,'WPI','Bio-Eng','Y')
insert into Apply values (345,'Cornell','Bio-Eng','N')
insert into Apply values (345,'Cornell','CS','Y')
insert into Apply values (345,'Cornell','EE','N')
insert into Apply values (678,'NJIT','Hist','Y')
insert into Apply values (987,'NJIT','CS','Y')
insert into Apply values (987,'Stoony Brook','CS','Y')
insert into Apply values (876,'NJIT','Bio','N')
insert into Apply values (876,'WPI','Marine-Bio','Y')
insert into Apply values (876,'WPI','Hist','N')
insert into Apply values (765,'NJIT','Hist','Y')
insert into Apply values (765,'Cornell','Hist','N')
insert into Apply values (765,'Cornell','Psych','Y')
insert into Apply values (543,'WPI','CS','N')
Basically I have to find the list of students id who belongs to major named as 'Cs' but not to the major 'EE'. I tried it by myself but it is not working properly.
Here is the code below:
select * from students
where s_id in (
select s_id
from apply
where major='CS' and Major!='EE'
group by s_id
)```
I would use exists and not exists:
select s.*
from students s
where
exists (select 1 from applies a where a.s_id = s._id and a.major = 'CS')
and not exists (select 1 from applies a where a.s_id = s._id and a.major = 'EE')
With an index on applies(s_id, major), this should be an efficient option.
Another approach is to join, aggregate, and filter with a having clause. This requires listing the columns that you want to show in both the select and group by clauses:
select s.s_id, s.s_name
from students s
inner join applies a on a.s_id = s.s_id
where a.major in ('CS', 'EE')
group by s.s_id, s.s_name
having
max(case when a.major = 'CS' then 1 else 0 end) = 1
and max(case when a.major = 'EE' then 1 else 0 end) = 0
Note: apply is a reserved word in a number a databases (SQL Serer, Oracle, ...), hence not a good choice for a table name. I renamed it to applies in the queries.

Query to display output horizontally

I need to display a query output in a horizontal manner. I have some example data
create table TestTable (id number, name varchar2(10))
insert into TestTable values (1, 'John')
insert into TestTable values (2, 'Mckensy')
insert into TestTable values (3, 'Valneech')
insert into TestTable values (4, 'Zeebra')
commit
select * from TestTable
This gets the output in a vertical view.
ID Name
==========
1 John
2 Mckensy
3 Valneech
4 Zeebra
However, I need to display it horizontally.
ID 1 2 3 4
Name John Mckensy Valneech Zeebra
How can one do this?
To pivot, you should use the pivot clause of the select statement:
select *
from testtable
pivot ( max(name)
for id in (1,2,3,4)
)
This is not particularly pretty to do in SQL, so you should consider carefully whether this is what you want to do. I normally use Oracle Base for pivoting examples but there are many out there.
Here's a little SQL Fiddle to demonstrate.
Maybe it will help you:
select 'id', LISTAGG(id, ' ') WITHIN GROUP (ORDER BY name)
from testtable
union
select 'name', LISTAGG(name, ' ') WITHIN GROUP (ORDER BY name)
from testtable
EDIT:
or with pivot:
create table TestTable2 (id varchar2(30), name varchar2(10));
insert into TestTable2 values ('id', 'name');
insert into TestTable2
select cast(id as varchar2(30)) as id , name
from testtable
select *
from testtable2
pivot ( max(name)
for id in ('id',1,2,3,4)
)
PIVOT operator is what you are looking for.

sql update query

I want to strip off all _ prefixes in the name column, but the result may cause a conflict. So if the result duplicates with existing ones, I want to suffix a _ to it until there's no duplication.
In the below example case, _test should be renamed to test___.
create table A
(
name VARCHAR2(20) unique,
id int
);
insert into a (name, id) values ('_test', 1);
insert into a (name, id) values ('test', 2);
insert into a (name, id) values ('test_', 3);
insert into a (name, id) values ('test__', 4);
Try this:
merge into A
using (with aa as (select id, trim('_' from name) name from A)
select rpad(name,
length(name) - 1 + row_number()
over(partition by name order by id),
'_') name2,
id
from AA) s
on (s.id = a.id)
when matched then
update set a.name = s.name2

SQL Server 2008 Before Insert Trigger

I have the following Query:
Insert into tblTest (ID, Name, Age) VALUES (1, 'TestName', 20);
In my trigger I want to check - if the query's ID is equal to 1, send another query:
Insert into tblTest (ID, Name, Age) VALUES (2, 'TestName', 21);
Else, dont do anything.
The problem is, I dont know how to keep the parameters as is and just change the age, so basically I want to send the SAME query, and change a certain parameter (in this case, its the age parameter).
The rows about to be inserted can be found in the special inserted table. Here's an example:
if object_id('tblTest') is not null
drop table tblTest
create table tblTest (id int, name varchar(50), age int)
go
create trigger trg_tblTest_BeforeInsert
on tblTest
after insert
as begin
insert tblTest
select id + 1
, name
, age + 1
from inserted
where id = 1 -- Only for rows with id=1
end
go
insert tblTest (id, name, age) values (1, 'TestName', 20)
select * from dbo.tblTest
This prints:
id name age
1 TestName 20
2 TestName 21

How to write the sql to findout which value is not in the table?

I am having a table Student and i have a set of 20 names.
by using his sql
select name from student st where st.name in (
'abc', 'xyz', . . .
)
i can find out all student names which are in table and in the set.
Now, how can i find out which out of these 20 names are not in Student table.
I'm assuming you want the names themselves.
One option is to create a table with all the available student names, then select from it rows which don't have corresponding rows in the student tables, it will look something like this
select name from student_names
where name not in (select name from students)
CREATE TABLE student(name VARCHAR(255));
INSERT INTO student VALUES('a'), ('abc');
CREATE TABLE temp(x VARCHAR(255));
INSERT INTO temp VALUES('abc'), ('xyz');
SELECT x FROM temp WHERE
NOT EXISTS (SELECT * FROM student st WHERE st.name = x);
Depending on the database you use, there might be an easier way. There is also a way using UNION.
SELECT NOT IN ?
postgresql: http://archives.postgresql.org/pgsql-sql/2002-08/msg00322.php
DECLARE #names table ( name varchar(100) )
INSERT INTO #names VALUES ('abc')
...
INSERT INTO #names VALUES ('xyz')
SELECT name FROM #names WHERE name NOT IN ( SELECT DISTINCT Name FROM Student )
select name from student where name not in (
select name from student st where st.name in (
'abc', 'xyz', . . .
))
EDIT: I might not get what you are looking for. Please run following script and it is giving the results.
declare #student table
(
name varchar(50)
)
insert into #student select 'james'
insert into #student select 'will'
insert into #student select 'bill'
insert into #student select 'adam'
insert into #student select 'jon'
insert into #student select 'white'
insert into #student select 'green'
select name from #student where name in ('james', 'will', 'bill')
select name from #student where name not in (select name from #student where name in ('james', 'will', 'bill'))
Assuming that the tool you are using can generate dynamic sql, try generating an inline view consisting of your set of user names - like so:
select 'abc' check_name union all
select 'xyz' check_name union all
...
(The syntax of the inline view may depend on which version of SQL you are using - some versions of SQL require a from [dummy_table] clause in select statements that are not accessing a table.)
Then construct a query using this inline view with a not exists in student clause, like this:
select check_name from (
select 'abc' check_name union all
select 'xyz' check_name union all
...
) ilv where not exists
(select null from student st where st.name = ilv.check_name)