Refactor querying hardcoded values in function - sql

Does anybody have any suggestions on how to refactor below better? I've renamed the item names to simplify.
I've only inherited this (for an import process) and it does not look very efficient to me especially with the hardcoded values in the function. I am looking at putting the hardcoded values into a table and refer to it instead of the function, but I'm not sure how to make that work yet based on the repetitive columns in the query.
MyTable
MyTableId INT,
MyTableOtherColumn VARCHAR(100),
MyTableDesc1 VARCHAR(10),
MyTableDesc2 VARCHAR(10),
. . .
MyTable24 VARCHAR(10),
MyTable25 VARCHAR(10),
etc.
MyFunction
RETURNS #myFunctionTable TABLE
(
myFunctionDesc VARCHAR(256),
myFunctionCode VARCHAR(10)
)
AS
BEGIN
INSERT INTO #myFunctionTable (myFunctionDesc, myFunctionCode) VALUES ('My Function Desc 1', 'MYCODE1');
INSERT INTO #myFunctionTable (myFunctionDesc, myFunctionCode) VALUES ('My Function Desc 2', 'MYCODE2');
. . .
INSERT INTO #myFunctionTable (myFunctionDesc, myFunctionCode) VALUES ('My Function Desc 99', 'MYCODE99');
INSERT INTO #myFunctionTable (myFunctionDesc, myFunctionCode) VALUES ('My Function Desc 100', 'MYCODE100');
END
SELECT
MyTableId,
MyTableOtherColumn,
. . .
(SELECT myFunctionCode FROM MyFunction() WHERE MyFunctionDesc = MyTableDesc1),
(SELECT myFunctionCode FROM MyFunction() WHERE MyFunctionDesc = MyTableDesc2),
. . .
(SELECT myFunctionCode FROM MyFunction() WHERE MyFunctionDesc = MyTableDesc24),
(SELECT myFunctionCode FROM MyFunction() WHERE MyFunctionDesc = MyTableDesc25),
FROM myTable T
JOIN . . .
WHERE . . .

Just use conditional aggregation and outer apply:
SELECT MyTableId, MyTableOtherColumn,
. . .
mf.val1, mv.val2, . . .
FROM myTable T JOIN
. . . OUTER APPLY
(SELECT MAX(CASE WHEN MyFunctionDesc = MyTableDesc1 THEN myFunctionCode END) as val1,
MAX(CASE WHEN MyFunctionDesc = MyTableDesc2 THEN myFunctionCode END) as val2,
. . .
FROM MyFunction()
) mf
WHERE . . .

Related

Omit record in group if another record is present in same group

I'm trying to remove a record from a group of results, if there is a record with a certain value within the same group. I tried to adapt my complex problem to a simple example:
DECLARE #fruits TABLE (type varchar(16), attribute varchar(16))
INSERT INTO #fruits VALUES('orange', 'juicy');
INSERT INTO #fruits VALUES('orange', 'seeds');
INSERT INTO #fruits VALUES('orange', 'pit');
INSERT INTO #fruits VALUES('apple', 'juicy');
INSERT INTO #fruits VALUES('apple', 'seeds');
INSERT INTO #fruits VALUES('apple', 'crisp');
SELECT * FROM #fruits;
Let's say I wanted to omit any record from my results that has an attribute='pit' if there is another fruit of the same type with attribute='seeds'.
How can I go about writing that query using SQL Server 2016?
You can use note exists and a little bit of boolean logic:
select f.*
from #fruits f
where
attribute <> 'pit'
or not exists (
select 1
from #fruits f1
where f1.type = f.type and f1.attribute = 'seeds'
)
This filters out records of attribute "pit" when the given type also has attribute "seeds".
It might be simpler to follow if the condition is expressed as a negation:
select f.*
from #fruits f
where not (
attribute = 'pit'
and exists (
select 1
from #fruits f1
where f1.type = f.type and f1.attribute = 'seeds'
)
An alternative uses window functions:
select *
from (
select
f.*,
max(case when attribute = 'seeds' then 1 else 0 end) over(partition by type) has_seeds
from #fruits f
) f
where not (attribute = 'pit' and has_seeds = 1)

mapping many to many items

I'm using database that looks like this the following:
CREATE TABLE Students(
[StudentId] [int],
...,
[MajorId] [int]
);
CREATE TABLE Majors(
[MajorId] [int],
...,
[MajorDes] [varchar](20)
);
CREATE TABLE CourseRequiredForEachMajor(
[MajorId] [int],
...,
[CourseTitle] [varchar](20)
);
CREATE TABLE CoursesCompletedByStudents(
[StudentId] [int],
...,
[CourseTitle][varchar] (20)
);
INSERT INTO Majors ([MajorId] , .. , [MajorDes]) VALUES (1, ... . 'IT');
INSERT INTO Students ([StudentId], .. , [MajorId]) VALUES (1, ... . 1);
INSERT INTO CourseRequiredForEachMajor ([MajorId], .. , [CourseTitle]) VALUES (1, ... . 'IT101');
INSERT INTO CourseRequiredForEachMajor ([MajorId], .. , [CourseTitle]) VALUES (1,...,'IT302');
INSERT INTO CourseRequiredForEachMajor ([MajorId], .. , [CourseTitle]) VALUES(1,...,'IT321');
INSERT INTO CoursesCompletedByStudents ([StudentId], .. , [CourseTitle]) VALUES (1, ... . 'IT101');
INSERT INTO CoursesCompletedByStudents ([StudentId], .. , [CourseTitle]) VALUES (1,...,'IT302');
INSERT INTO CoursesCompletedByStudents ([StudentId], .. , [CourseTitle]) VALUES(2,...,'IT321');
I'm trying to list the missing courses for each student in order to complete the all the requirements for each major ( e.g. in the image above, I want to say that studentId# 1 need to take course IT321 in order to complete all requirement for majorId #1 ).
Also is there anyway that I can do to show percentage of completion ? ( e.g. studentId#1 completed two courses ( 66.6% ) out of 3 courses that are required by the major ). what is the way to do the calculations of this.
I really have no idea how to solve this, but this is my attempt:
Select CoursesCompletedByStudents.CourseTitle from Students,MajorsCourseRequiredForEachMajor,CoursesCompletedByStudents
where Students.MajorId= Major.MajorId and Studetns.StudentId = CoursesCompletedByStudents.[StudentId]
and CourseRequiredForEachMajor.[CourseTitle]=CoursesCompletedByStudents.[CourseTitle]
This query would give the required result.
with coursesCTE as
(
Select StudentId, CourseTitle, m.MajorId
from Students s
join Majors m
on s.MajorId = m.MajorID
join CourseRequiredForEachMajor cr
on cr.MajorId = m.MajorID
),
completedCTE
as
(
Select StudentId, cc.courseTitle, MajorId
from CoursesCompletedByStudents cc
join CourseRequiredForEachMajor cm
on cc.CourseTitle = cm.CourseTitle
)
Select * from coursesCTE
except
Select * from completedCTE
If you want comma separated course Ids, you can use the Stuff/XML path hack or STRING_AGG if you're using SQL Server 2017

How to retrieve id from one table on the basis of string and store it as int in another table?

I have a companyId cid which is a int type
present in two tables
companydet
opprt
i have a problem that i'm trying to retrieve cid from companydet on the basis of cname comapny name which is string after retriving this id im trying to store it opprt which is an int type
i have tried this code
select c.cid
from companydet c
where cname='google'
and insert into opprt( cid,oppdetails,oppfp,oppap,oppcd,oppd )
values('#c.cid','abc','','','','')
but its not working please help me with this and explain me how can we do this ?
You can use an insert...select for this:
insert into opprt( cid,oppdetails,oppfp,oppap,oppcd,oppd )
select cid,'abc','','','',''
from companydet
where cname='google'
I think you want insert . . . select:
insert into opprt( cid, oppdetails, oppfp, oppap, oppcd, oppd )
select c.cid, 'abc', '', '', '', ''
from companydet c
where cname = 'google' ;
to Insert into table using another table
insert into opprt( cid,oppdetails,oppfp,oppap,oppcd,oppd )
Select Columnname,Columnname1,Colummname2,Columnname3,...etc from companydet
where cname='google'
to insert values using static ones
insert into opprt( cid,oppdetails,oppfp,oppap,oppcd,oppd )
Values(cid,'abc','','','','')
you need to use insert into .... select statement .
You have also disucss that cid in opprt is int and cid in companydet is varchar , so you need to cat cid to int .
Please follow my code .
insert into opprt( cid,oppdetails,oppfp,oppap,oppcd,oppd )
select CAST(cid as int),'abc','','','',''
from companydet
where cname='google'
Thanks .
You might wanna try this too:
declare #d_cid int
select #d_cid = c.cid from companydet c where cname='google'
insert into opprt( cid,oppdetails,oppfp,oppap,oppcd,oppd )
values(#d_cid,'abc','','','','')

Update table using random of multiple values in other table

Consider this data:
CREATE TABLE #Data (DataID INT, Code VARCHAR(2), Prefix VARCHAR(3))
INSERT INTO #Data (DataID, Code)
VALUES (1, 'AA')
, (2, 'AA')
, (3, 'AA')
, (4, 'AA')
, (5, 'AA')
, (6, 'AA')
CREATE TABLE #Prefix (Code VARCHAR(2), Prefix VARCHAR(3))
INSERT INTO #Prefix (Code, Prefix)
VALUES ('AA', 'ABC')
, ('AA', 'DEF')
, ('AA', 'GHI')
, ('AA', 'JKL')
I want to set the Prefix value in #Data to be a random Prefix from #Prefix with a matching Code.
Using a straight inner join just results in one value being used:
UPDATE D
SET Prefix = P.Prefix
FROM #Data AS D
INNER JOIN #Prefix AS P ON D.Code = P.Code
From reading other questions on here, NEWID() is recommended as a way of randomly ordering something. Changing the join to:
SELECT TOP 1 subquery ordering by NEWID()
still only selects a single value (though random each time) for every row:
UPDATE D
SET Prefix = (SELECT TOP 1 P.Prefix FROM #Prefix AS P WHERE P.Code = D.Code ORDER BY NEWID())
FROM #Data AS D
So, I'm not sure how to get a random prefix for each data entry from a single update statement. I could probably do some kind of loop through the #Data table, but I avoid ever touching loops in SQL and I'm sure that would be slow. The actual application of this will be on tens of thousands of records, with hundreds of prefixes for dozens of codes.
This is how to do it:
UPDATE d SET Prefix = ca.Prefix
FROM #Data d
CROSS APPLY(SELECT TOP 1 Prefix
FROM #Prefix p
WHERE d.DataID = d.DataID AND p.Code = d.Code ORDER BY NEWID()) ca
Notice d.DataID = d.DataID. This is here to force Sql Server engine to reevaluate subquery for each row in #Data table.

select items where column NOT IN itemList

QuickExplain :My elementList is [1, 2, 3, 4] and if 3, 4 is not present in table I want 3, 4.
PS. If you use "NOT IN" this returns you values from table But I want only elements from elementList I queried.
You can use a temporary table:
create table #elements (name varchar(50))
insert into #elements (name) values ('1')
insert into #elements (name) values ('2')
insert into #elements (name) values ('3')
insert into #elements (name) values ('4')
select name
from #elements
where name not in (select col1 from tab);
drop table #elements
Try doing the reverse whatever you are doing. If you want only elements from element list then try this
select elements from elementList where col1 not in (select col1 from table)
A bit verbose but solves the purpose cleanly
select * from
(select 'item1' as items UNION
select 'item2' as items UNION
.
.
.
select 'itemN' as items ) as notFoundItemList where items NOT IN
(
Select ITEM from table WHERE AND itemName in
)