Need to get value from a lookup table - sql

I have a table-X with ecode,emp ID ( some values)
37,10
47,20
57,30
There are 2 lookup tables
lookup table 1 has just the emp ID details( which am interested in)
10
20
so when i join..i get all the values needed (thats one part)
my result will be
37 10
47 20
second part is,
the ones which doesnt satisfy the join condition should lookup on table 2 which has
2 columns
ecode, other_codes
37 xxx
47 YYY
57 AAA
So when 30 comes in , i want to return AAA and my final dataset should be,
37, 10
47,20
57 AAA
appreciate any help!
Thanks

You can left join both tables and use CASE statement for selecting a value from one table or the other.
I've created a db-fiddle which I think exemplifies your situation based on your description: https://www.db-fiddle.com/f/ujW8Unf44CqbsiJZXqXXtK/0
Here is the code for posterity. To set up your tables:
CREATE TABLE tableX (
eCode int,
employeeId int
);
INSERT INTO tableX (eCode, employeeId) VALUES (37, 10);
INSERT INTO tableX (eCode, employeeId) VALUES (47, 20);
INSERT INTO tableX (eCode, employeeId) VALUES (57, 30);
CREATE TABLE employeeIds (employeeId int);
INSERT INTO employeeIds (employeeId) VALUES (10);
INSERT INTO employeeIds (employeeId) VALUES (20);
CREATE TABLE otherCodes (
eCode int,
other_codes varchar(10)
);
INSERT INTO otherCodes (eCode, other_codes) VALUES (37, 'XXX');
INSERT INTO otherCodes (eCode, other_codes) VALUES (47, 'YYY');
INSERT INTO otherCodes (eCode, other_codes) VALUES (57, 'AAA');
The query based on this schema:
SELECT
tx.eCode,
CASE WHEN ei.employeeId IS NULL THEN oc.other_codes ELSE ei.employeeId END as 'result'
FROM tableX tx
LEFT JOIN employeeIds ei ON tx.employeeId = ei.employeeId
LEFT JOIN otherCodes oc ON tx.eCode = oc.eCode;

Related

How to retrieve SCOPE_IDENTITY of all inserts done in INSERT INTO [table] SELECT [col1, ...] [duplicate]

This question already has answers here:
SQL Server - Return value after INSERT
(14 answers)
Closed 7 months ago.
Suppose I have a temp table with some cols one of which I have dedicated to identity column of the inserted Invoice and the others for inserting Invoice data itself. Like the following table :
CREATE TABLE #InvoiceItems
(
RowNumber INT, -- Used for inserting new invoice
SaleID INT, -- Used for inserting new invoice
BuyerID INT, -- Used for inserting new invoice
InvoiceID INT -- Intended for PK of the invoice added after inserting it
);
I use something like the following for inserting data into Invoice table
INSERT INTO [Invoice]
SELECT [col1, ...]
FROM #InvoiceItems
How can I achieve to fill the InvoiceID column while inserting table data into Invoice table using temp table? I know about SCOPE_IDENTITY() function but it returns the last inserted PK only which does not really suit my need.
I could also use a while to do this one by one but since the number of data I'm planning to insert is immense, I feel like it's not going to be the most optimized option.
Thanks for the answers in advance.
To grab multiple IDENTITY values from INSERT INTO SELECT FROM OUTPUT clause could be used:
-- temp table
CREATE TABLE #temp(col VARCHAR(100));
INSERT INTO #temp(col) VALUES ('A'), ('B'), ('C');
--target table
CREATE TABLE tab(
id INT IDENTITY,
col VARCHAR(100)
);
Main insert:
INSERT INTO tab(col)
OUTPUT inserted.id, inserted.col
SELECT col
FROM #temp;
The output could be also Inserted into another table using OUTPUT INTO:
CREATE TABLE #temp_identity(id INT);
INSERT INTO tab(col)
OUTPUT inserted.id
INTO #temp_identity
SELECT col
FROM #temp;
SELECT * FROM #temp_identity;
db<>fiddle demo
CREATE TABLE #InvoiceItems(
RowNumber INT,
SaleID INT,
BuyerID INT,
InvoiceID INT
);
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 55, 77)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 56, 78)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 57, 79)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 58, 80)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 59, 81)
DECLARE #Inserted table( RowNumber int,
SaleID INT,
BuyerID INT,
InvoiceID INT);
INSERT INTO dbo.[Invoice] (RowNumber, SaleID, BuyerID)
OUTPUT INSERTED.RowNumber, INSERTED.SaleID, INSERTED.BuyerID, INSERTED.InvoiceID
INTO #Inserted
SELECT RowNumber, SaleID, BuyerID
FROM #InvoiceItems
UPDATE ii
SET InvoiceID = ins.InvoiceID
FROM #InvoiceItems ii
JOIN #Inserted ins on ins.BuyerID = ii.BuyerID and ins.RowNumber = ii.RowNumber and ins.SaleID = ii.SaleID
SELECT * FROM #InvoiceItems

How to insert a record into a table - depending on the total requiredQty from another table?

I have this row in the database table:
ID requiredQty
1088 30
And another table:
ID orderLineID bookedInQty
3000 1088 10
3001 1088 10
dbfiddle: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=9ecd8c83fcda08453481ec6d0ce45947
Summary
Total booked in quantity is total of 20 and 10 remaining for that particular order-line.
Question
How can I create an if statement to insert a record into the 2nd table, not to exceed table 1 requiredQty: 30?
Example
If insert bookedInQty: 11 this means it exceeds 30 because there is an extra 1. If it exceeds, simply do nothing.
If to insert bookedInQty: 9 this does not exceeds 30 because the total now equals to 29. Then insert this record.
Note
Without creating any extra tables, I am trying to do it using an if statement.
This uses if to check if the sum of the bookedQty and the new value are lower then the required quantity. You can put the code in a stored procedure.
create table table1(
id int NOT NULL,
requiredQty int
);
create table table2(
id int NOT NULL,
orderLineId int,
bookedInQty int
);
insert into table1(id, requiredQty) VALUES (1088, 30);
insert into table2(id, orderLineId, bookedInQty)
VALUES
(3000, 1088, 10),
(3001, 1088, 10);
declare #sumQty int, #newQty int, #newOrderLineId int;
select #newOrderLineId = 1088, #newQty = 11; -- change #newQty to 10 or lower
select #sumQty = sum(bookedInQty) from table2 where orderLineId = #newOrderLineId
group by orderLineId;
-- I hardcoded the value of id, it should add 1 to the maximum value or use an identity column
if exists(select * from table1 where id = #newOrderLineId and requiredQty >= #sumQty + #newQty)
insert table2 (id, orderLineId, bookedInQty) values (3002, #newOrderLineId, #newQty);
select * from table1;
select * from table2;
Dbfiddle demo:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d800624279381f9bbd71cf51bbc5351a

SQL request multiple selects

SQL Request:
The numClient, nomClient, numClient, numTel of Client, the total amount ordered
For the articles dispendic which prixUnitaire is > 2000, and total amount ordered of articles modic which prixUnitaire is < 1500
for clients who ordered a amount of dispendic articles < amount ordered for modic articles.
here are the associated tables
Client (numClient, nomClient, numTel)
Article (numArticle, decription, prixUnitaire,qtéEnStock)
Commande (numCde, dateCde, numClient#)
LigneCommande (numCde#, numArticle#, qté)
Livraison (numLiv, dateLiv)
DetailLiv (numLiv#, numCde#, numArticle#, qtéLiv)
My understanding:
amount means number of items (quantity) not total value (quantity * price).
the query only has to consider orders, so "commande", not "livraison"
dispendic means price > 2000; modic means price < 1500. (I don't
know these words; are they specific to your business?)
You don't mention which database you are using. I used PostgreSQL, but it is all standard SQL so should work on any standard relational database.
Set-up
create table client
(
num_client integer,
nom_client varchar(16),
num_tel varchar(20),
constraint primary_key_client primary key (num_client)
);
create table article
(
num_article integer,
description varchar(16),
prix_unitaire decimal(9,2),
quantite_en_stock integer,
constraint primary_key_article primary key (num_article)
);
create table commande
(
num_commande integer,
date_commande date,
num_client integer,
constraint primary_key_commande primary key (num_commande),
constraint foreign_key_commande_client foreign key (num_client) references client(num_client)
);
create table ligne_commande
(
num_commande integer,
num_article integer,
quantite integer,
constraint foreign_key_ligne_commande_commande foreign key (num_commande) references commande(num_commande),
constraint foreign_key_ligne_commande_article foreign key (num_article) references article(num_article)
);
insert into client (num_client, nom_client, num_tel) values (123, 'Dubois', '1 41 17 86 62');
insert into client (num_client, nom_client, num_tel) values (456, 'Bochet', '1 35 32 65 58');
insert into article (num_article, description, prix_unitaire, quantite_en_stock) values (79362, 'chaise', 1499.00, 36);
insert into article (num_article, description, prix_unitaire, quantite_en_stock) values (83746, 'placard', 2001.00, 14);
insert into commande (num_commande, date_commande, num_client) values (10030, '2018-01-13', 123);
insert into commande (num_commande, date_commande, num_client) values (10019, '2018-01-12', 456);
insert into ligne_commande (num_commande, num_article, quantite) values (10030, 79362, 4);
insert into ligne_commande (num_commande, num_article, quantite) values (10030, 83746, 1);
insert into ligne_commande (num_commande, num_article, quantite) values (10019, 79362, 1);
insert into ligne_commande (num_commande, num_article, quantite) values (10019, 83746, 1);
insert into ligne_commande (num_commande, num_article, quantite) values (10019, 83746, 1);
Query
select
a.num_client,
a.nom_client,
a.num_tel,
dispendic.sum_quantite as dispendic_amount,
modic.sum_quantite as modic_amount
from
client a
join
commande b
on a.num_client = b.num_client
join
(
select
num_commande,
sum(quantite) as sum_quantite
from
ligne_commande w
join
article x
on w.num_article = x.num_article
where
x.prix_unitaire < 1500
group by
num_commande
) modic
on b.num_commande = modic.num_commande
join
(
select
num_commande,
sum(quantite) as sum_quantite
from
ligne_commande w
join
article x
on w.num_article = x.num_article
where
x.prix_unitaire > 2000
group by
num_commande
) dispendic
on b.num_commande = dispendic.num_commande
where
dispendic.sum_quantite < modic.sum_quantite;
Result:
num_client | nom_client | num_tel | dispendic_amount | modic_amount
------------+------------+---------------+------------------+--------------
123 | Dubois | 1 41 17 86 62 | 1 | 4
(1 row)

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

SQL Server field calculation based on multiple condition

Here is my scenario:
I have a Person table with following fields.
create table Person(PersonID int primary key identity(1,1),
Age int,
height decimal(4,2),
weight decimal(6,2)
);
insert into Person(Age,height,weight) values (60,6.2,169); -- 1
insert into Person(Age,height,weight) values (15,5.1,100); -- 2
insert into Person(Age,height,weight) values (10,4.5,50); -- 3
What I need to do is,
if the person Age >= 18 and height >= 6 then calculationValue = 20
if the person Age >= 18 and height < 6 then calculationValue = 15
if the person Age < 18 and weight >= 60 then calculationValue = 10
if the person Age < 18 and weight < 60 then calculationValue = 5
based on these condition I need to find the calculationValue and do some math.
I tried to make a flexible model so in future it would be easier to add any more conditions and can easily change the constant values (like 18, 6, 60 etc)
I created couple of tables as below:
create table condTable(condTableID int primary key identity(1,1),
condCol varchar(20),
startValue int,
endValue int
);
insert into condTable(condCol,startValue,endValue) values ('Age',18,999) -- 1
insert into condTable(condCol,startValue,endValue) values ('Height',6,99) -- 2
insert into condTable(condCol,startValue,endValue) values ('Height',0,5.99) -- 3
insert into condTable(condCol,startValue,endValue) values ('Age',0,17) -- 4
insert into condTable(condCol,startValue,endValue) values ('Weight',60,999) -- 5
insert into condTable(condCol,startValue,endValue) values ('Weight',0,59) -- 6
I join two condition to make it one in the following table as given by the requirement.(ie. if age >=18 and height >=6 then calculationValue = 20. etc)
create table CondJoin(CondJoin int,condTableID int,CalculationValue int)
insert into CondJoin values (1,1,20)
insert into CondJoin values (1,2,20)
insert into CondJoin values (2,1,15)
insert into CondJoin values (2,3,15)
insert into CondJoin values (3,4,10)
insert into CondJoin values (3,5,10)
insert into CondJoin values (4,4,5)
insert into CondJoin values (4,6,5)
I think this model will provide the flexibility of adding more conditions in future. But I am having difficulties on implementing it in SQL Server 2005. Anyone can write a sql that process in set basis and compare the value in Person table with CondJoin table and provide the corresponding calculationvalue. For eg. for person ID 1 it should look at CondJoin table and give the calculationValue 20 since his age is greater than 18 and height is greater than 6.
this looks like you are headed towards dynamic sql generation.
i think maybe you would be better off with a row for each column and cutoff values for the ranges, and a value if true ... maybe something like:
age_condition
-----------------
min_age
max_age
value
this is something that you could populate and then query without some dynamic generation.
The following is extremely rough but it should get the point across. It normalizes the data and moves towards a semi-object oriented (attribute/value/attribute value) structure. I'll leave it up to you to reinforce referential integrity, but the following is flexible and will return the results you want:
CREATE TABLE Person (
PersonID INT PRIMARY KEY IDENTITY(1,1)
,Name NVARCHAR(255)
);
GO
CREATE TABLE PersonAttribute (
PersonID INT
,CondAttributeID INT
,Value NVARCHAR(255)
);
GO
CREATE TABLE CondAttribute (
AttributeID INT PRIMARY KEY IDENTITY(1,1)
,Attribute NVARCHAR(255));
GO
CREATE TABLE CondTable (
CondTableID INT PRIMARY KEY IDENTITY(1,1)
,CondAttributeID INT
,StartValue MONEY
,EndValue MONEY
);
GO
CREATE TABLE CalculationValues (
CalculationID INT PRIMARY KEY IDENTITY(1,1)
,CalculationValue INT
);
GO
CREATE TABLE CondCalculation (
CondTableID INT
,CalculationID INT
);
INSERT Person (Name)
VALUES ('Joe')
,('Bob')
,('Tom');
INSERT PersonAttribute (
PersonID
,CondAttributeID
,Value
)
VALUES (1, 1, '60')
,(1, 2, '6.2')
,(1, 3, '169')
,(2, 1, '15')
,(2, 2, '5.1')
,(2, 3, '100')
,(3, 1, '10')
,(3, 2, '4.5')
,(3, 3, '50');
INSERT CondAttribute (Attribute)
VALUES ('Age')
,('height')
,('weight');
INSERT CondTable (
CondAttributeID
,StartValue
,EndValue)
VALUES (1,18,999) --Age
,(2,6,99) --Height
,(2,0,5.99) -- Height
,(1,0,17) -- Age
,(3,60,999) -- Weight
,(3,0,59); -- Weight
INSERT CalculationValues (CalculationValue)
VALUES (5)
,(10)
,(15)
,(20);
INSERT CondCalculation (CondTableID, CalculationID)
VALUES (1,4)
,(2,4)
,(1,3)
,(3,3)
,(4,2)
,(5,2)
,(5,1)
,(6,1);
SELECT *
FROM Person AS p
JOIN PersonAttribute AS pa ON p.PersonID = pa.PersonID
JOIN CondAttribute AS ca ON pa.CondAttributeID = ca.AttributeID
JOIN CondTable AS ct ON ca.AttributeID = ct.CondAttributeID
AND CONVERT(money,pa.Value) BETWEEN ct.StartValue AND ct.EndValue
JOIN CondCalculation AS cc ON cc.CondTableID = ct.CondTableID
JOIN CalculationValues AS c ON cc.CalculationID = c.CalculationID
WHERE p.PersonID = 1
The following solution uses PIVOT (twice) to transform the combination of CondJoin and condTable into a chart, then joins the chart to the Person table to calculate the target value. I believe, a series of CASE expressions could be used instead just as well. Anyway...
All the tables have been turned into table variables, for easier testing. So first, DDL and data preparation:
declare #Person table(PersonID int primary key identity(1,1),
Age int,
height decimal(4,2),
weight decimal(6,2)
);
insert into #Person(Age,height,weight) values (60,6.2,169); -- 1
insert into #Person(Age,height,weight) values (15,5.1,100); -- 2
insert into #Person(Age,height,weight) values (10,4.5,50); -- 3
declare #condTable table(condTableID int primary key identity(1,1),
condCol varchar(20),
startValue int,
endValue int
);
insert into #condTable(condCol,startValue,endValue) values ('Age',18,999) -- 1
insert into #condTable(condCol,startValue,endValue) values ('Height',6,99) -- 2
insert into #condTable(condCol,startValue,endValue) values ('Height',0,5.99) -- 3
insert into #condTable(condCol,startValue,endValue) values ('Age',0,17) -- 4
insert into #condTable(condCol,startValue,endValue) values ('Weight',60,999) -- 5
insert into #condTable(condCol,startValue,endValue) values ('Weight',0,59) -- 6
declare #CondJoin table(CondJoin int,condTableID int,CalculationValue int);
insert into #CondJoin values (1,1,20)
insert into #CondJoin values (1,2,20)
insert into #CondJoin values (2,1,15)
insert into #CondJoin values (2,3,15)
insert into #CondJoin values (3,4,10)
insert into #CondJoin values (3,5,10)
insert into #CondJoin values (4,4,5)
insert into #CondJoin values (4,6,5)
And now the query:
;with startValues as (
select
CondJoin,
Age,
Height,
Weight,
CalculationValue
from (
select
j.CondJoin,
j.CalculationValue,
t.condCol,
t.startValue
from #CondJoin j
inner join #condTable t on j.condTableID = t.condTableID
) j
pivot (
max(startValue) for condCol in (Age, Height, Weight)
) p
),
endValues as (
select
CondJoin,
Age,
Height,
Weight,
CalculationValue
from (
select
j.CondJoin,
j.CalculationValue,
t.condCol,
t.endValue
from #CondJoin j
inner join #condTable t on j.condTableID = t.condTableID
) j
pivot (
max(endValue) for condCol in (Age, Height, Weight)
) p
),
combinedChart as (
select
s.CondJoin,
AgeFrom = s.Age,
AgeTo = e.Age,
HeightFrom = s.Height,
HeightTo = e.Height,
WeightFrom = s.Weight,
WeightTo = e.Weight,
s.CalculationValue
from startValues s
inner join endValues e on s.CondJoin = e.CondJoin
)
select
p.*,
c.CalculationValue
from #Person p
left join combinedChart c
on (c.AgeFrom is null or p.Age between c.AgeFrom and c.AgeTo)
and (c.HeightFrom is null or p.Height between c.HeightFrom and c.HeightTo)
and (c.WeightFrom is null or p.Weight between c.WeightFrom and c.WeightTo)