I have a table (say A) that gives me currency conversion from a currency to USD. Lets say I have 3 currencies for now.
using this table I want to create the following output table (say B).
For example, AED to ARS would be 3.67/18.87 = .19
Imagine I have 70 from currencies in table A. This becomes hard to calculate manually. I am trying to do this in SSMS.
Would be great to have an approach.
Thanks in advance
You can retrieve the combination of all exchange values by taking a cartesian product of the table with itself. We can use CROSS JOIN for the same.
As the toCurrency is USD in all cases, we can directly divide the 'from' values of the 2 tables to derive other combinations of from and to Currencies. An example snippet of code is as follows:
DROP TABLE IF EXISTS currencyExchangeBase
CREATE TABLE currencyExchangeBase ( fromCode varchar(3),
toCode varchar(3),
exchangeValue numeric(19, 2) )
INSERT INTO currencyExchangeBase
VALUES ('AED','USD',3.67),('ARS','USD',18.87), ('AUD','USD',1.28205);
SELECT b1.fromCode AS fromCode,
b2.fromCode AS toCode,
b1.exchangeValue/b2.exchangeValue AS exchangeValue
FROM currencyExchangeBase b1
CROSS JOIN currencyExchangeBase b2
Related
I have a table and want to get the average score for each student。
To be more specific, scoremonth1 has more weight to be calculated than 2,3,4,5 and 6 (1>2>3>4>5>6). And we should add no more than 3 monthly scores from the table.
For instance, the average score for Tom should be (80+90)/2 since there are only 2 scores available. As for Marry, the average score should be (90+70+80)/3 since those are the three monthly scores with more weight. And again, for Anna, the average score should be (90+100+70)/3
In my case, there would be over 100 students. Except listing all the possible cases like CASE WHEN scoremonth1 is not null, scoremonth2 is NULL . etc to calculate the average, what else method could do the calculation dynamically?
I know there is a SQL function coalesce to return the first not null value, but how could I get the second and third not null values? And is there a way to track which monthlyscores are added up? I really appreciate your help!
Stu mentioned your underlying issue. To normalize your data without changing table design you can use cross apply...
select student, sum(score)
from table
cross apply (
values(1,scoremonth1),(2,scoremonth2),(3,scoremonth3)) as scores(month,score)
group by student
I strongly suggest you redesign so you don't have to manage this query when adding months by creating a new table called studentScores.
create table studentscores
(
student varchar(200)
,scoremonth int
,score decimal(5,2)
)
And then populate it like this...
insert into studentScores(student,scoremonth,score)
select *
from table
cross apply
(values
(student,1,scoremonth1)
,(student,2,scoremonth2)
,(student,3,scoremonth3)
,(student,4,scoremonth4)
,(student,5,scoremonth5)
) ca(ca1,ca2,ca3)
where ca3 is not null
And finally, usse it like this...
select ss.student, sum(score), count(*) NumOfScores, sum(score)/Count(*) avg
from table
join studentscores ss on ss.student=table.student
where ss.scoremonth between 1 and 3
group by ss.student
I'm learning how to create tables in SQL pulling data from existing tables from two different databases. I am trying to create a table combining two tables without duplicates. I've seen some say using UNION but I could not get that to work.
Say TABLE 1 has 2 COLUMNS (IdNumber, Material) and TABLE 2 has 3 COLUMNS (IdNumber, Size, Description)
How can I create a new table (named TABLE3) that combines those two but only shows the columns (PartDescription, Weight, Color) but without duplicates.
What I have done so far is as follows:
CREATE TABLE #Materialsearch (IdNumber varchar(30), Material varchar(30))
CREATE TABLE #Sizesearch (idnumber varchar(30), Size varchar(30), Description varchar(50))
INSERT INTO #Materialsearch (IdNumber, Material)
SELECT [IdNumber],[Material]
FROM [datalist].[dbo].[Table1]
WHERE Material LIKE 'Steel' AND IdNumber NOT LIKE 'Steel'
INSERT INTO #Sizesearch (idnumber, Size, Description)
SELECT [idNumber],[itemSize], [ShortDesc]
FROM [515dap].[dbo].[Table2]
WHERE itemSize LIKE '1' AND idnumber NOT LIKE 'Steel'
SELECT DISTINCT #Materialsearch.IdNumber, #Materialsearch.Material,
#Sizesearch.Size, #Sizesearch.Description
FROM #Materialsearch
INNER JOIN #Sizesearch
ON #Materialsearch.IdNumber = #Sizesearch.idnumber
ORDER BY #Materialsearch.IdNumber
DROP TABLE #Materialsearch
DROP TABLE #Sizesearch
This would show all items that are made from steel but do not have steel as their itemid's.
Thanks for your help
I'm not 100% sure what you're after - but you may find this useful.
You could use a FULL OUTER JOIN which takes takes all rows from both tables, matches the ones it can, then reports all rows.
I'd suggest (for your understanding) running
SELECT A.*, B.*
FROM #Materialsearch AS A
FULL OUTER JOIN #Sizesearch AS B ON A.[IdNumber] = B.[IdNumber]
Then to get the relevant data, you just need some tweaks on that e.g.,
SELECT
ISNULL(A.[IdNumber], B.[IdNumber]) AS [IdNumber],
A.Material,
B.Size,
B.Description
FROM #Materialsearch AS A
FULL OUTER JOIN #Sizesearch AS B ON A.[IdNumber] = B.[IdNumber]
Edit: Changed typoed INNER JOINs to FULL OUTER JOINs. Oops :( Thankyou very much #Thorsten for finding it!
I would like to create a product table. This product has unique part numbers. However, each part number has various number of previous part numbers, and various number of machines where the part can be used.
For example the description for part no: AA1007
Previous part no's: AA1001, AA1002, AA1004, AA1005,...
Machine brand: Bosch, Indesit, Samsun, HotPoint, Sharp,...
Machine Brand Models: Bosch A1, Bosch A2, Bosch A3, Indesit A1, Indesit A2,....
I would like to create a table for this, but I am not sure how to proceed. What I have been able to think is to create a table for Previous Part no, Machine Brand, Machine Brand Models individually.
Question: what is the proper way to design these tables?
There are of course various ways to design the tables. A very basic way would be:
You could create tables like below. I added the columns ValidFrom and ValidTill, to identify at which time a part was active/in use.
It depends on your data, if datatype date is enough, or you need datetime to make it more exactly.
CREATE TABLE Parts
(
ID bigint NOT NULL
,PartNo varchar(100)
,PartName varchar(100)
,ValidFrom date
,ValidTill date
)
CREATE TABLE Brands
(
ID bigint NOT NULL
,Brand varchar(100)
)
CREATE TABLE Models
(
ID bigint NOT NULL
,BrandsID bigint NOT NULL
,ModelName varchar(100)
)
CREATE TABLE ModelParts
(
ModelsID bigint NOT NULL
,PartID bigint NOT NULL
)
Fill your data like:
INSERT INTO Parts VALUES
(1,'AA1007', 'Screw HyperFuturistic', '2017-08-09', '9999-12-31'),
(1,'AA1001', 'Screw Iron', '1800-01-01', '1918-06-30'),
(1,'AA1002', 'Screw Steel', '1918-07-01', '1945-05-08'),
(1,'AA1004', 'Screw Titanium', '1945-05-09', '1983-10-05'),
(1,'AA1005', 'Screw Futurium', '1983-10-06', '2017-08-08')
INSERT INTO Brands VALUES
(1,'Bosch'),
(2,'Indesit'),
(3,'Samsung'),
(4,'HotPoint'),
(5,'Sharp')
INSERT INTO Models VALUES
(1,1,'A1'),
(2,1,'A2'),
(3,1,'A3'),
(4,2,'A1'),
(5,2,'A2')
INSERT INTO ModelParts VALUES
(1,1)
To select all parts of a certain date (in this case 2013-03-03) of the "Bosch A1":
DECLARE #ReportingDate date = '2013-03-03'
SELECT B.Brand
,M.ModelName
,P.PartNo
,P.PartName
,P.ValidFrom
,P.ValidTill
FROM Brands B
INNER JOIN Models M
ON M.BrandsID = B.ID
INNER JOIN ModelParts MP
ON MP.ModelsID = M.ID
INNER JOIN Parts P
ON P.ID = MP.PartID
WHERE B.Brand = 'Bosch'
AND M.ModelName = 'A1'
AND P.ValidFrom <= #ReportingDate
AND P.ValidTill >= #ReportingDate
Of course there a several ways to do an historization of data.
ValidFrom and ValidTill (ValidTo) is one of my favourites, as you can easily do historical reports.
Unfortunately you have to handle the historization: When inserting a new row - in example for your screw - you have to "close" the old record by setting the ValidTill column before inserting the new one. Furthermore you have to develop logic to handle deletes...
Well, thats a quite large topic. You will find tons of information in the world wide web.
For the part number table, you can consider the following suggestion:
id | part_no | time_created
1 | AA1007 | 2017-08-08
1 | AA1001 | 2017-07-01
1 | AA1002 | 2017-06-10
1 | AA1004 | 2017-03-15
1 | AA1005 | 2017-01-30
In other words, you can add a datetime column which versions each part number. Note that I added a primary key id column here, which is invariant over time and keeps track of each part, despite that the part number may change.
For time independent queries, you would join this table using the id column. However, the part number might also serve as a foreign key. Off the top of my head, if you were generating an invoice from a previous date, you might lookup the appropriate part number at that time, and then join out to one or more tables using that part number.
For the other tables you mentioned, I do not see a similar requirement.
I have two tables bottle and case that are filled out. They both have a column labeled case_id however in bottle table all the values are 0 while in case table they have the correct id.
How can I update the first table bottle values 0 with the new values from other table case? I believe I will need to use an UPDATE or INSERT or INNER JOIN.
If you give more detail for table struct will be better
UPDATE b SET b.case_id=c.case_id
FROM bottle AS b INNER JOIN [Case] AS c ON b.some_coloumn=c.some_cloumn
So I have two tables which will store sales figures for products. Table one holds the last 6 weeks sales figures for each product and table 2 shows the last 12 months. I need to find a way to compare these two tables to then produce a 3rd table which will contain the difference between the 2 values as column 2 as well as the products Sage code in column one. What would be the most efficient (in terms of time) way to do this as there will be a fair amount of products to compare and it will only continue to grow? The product Sage code is the key identifier here. The two tables are created as below.
IF OBJECT_ID('tempdb..#Last6WeeksProductSales') IS NOT NULL DROP TABLE #Last6WeeksProductSales;
CREATE TABLE #Last6WeeksProductSales
(
CompoundSageCode varchar(200),
Value decimal(18,2)
)
INSERT INTO #Last6WeeksProductSales
SELECT [SalesOrderLine].[sProductSageCode] AS [CompoundSageCode],
SUM([SalesOrderLine].[fQtyOrdered] * [SalesOrderLine].[fPricePerUnit]) AS [Value]
FROM [SalesOrderLine]
INNER JOIN [SalesOrder] ON (SalesOrder.iSalesOrderID = SalesOrderLine.iSalesOrderID)
WHERE [SalesOrder].[dOrderDateTime] > DateAdd("ww", -6, CURRENT_TIMESTAMP)
GROUP BYsProductSageCode;
SELECT * FROM #Last6WeeksProductSales
ORDER BY CompoundSageCode;
IF OBJECT_ID('tempdb..#Last12MonthsProductSales') IS NOT NULL DROP TABLE #Last12MonthsProductSales;
CREATE TABLE #Last12MonthsProductSales
(
CompoundSageCode varchar(200),
Value decimal(18,2)
)
INSERT INTO #Last12MonthsProductSales SELECT [SalesOrderLine].[sProductSageCode] AS [CompoundSageCode],
SUM([SalesOrderLine].[fQtyOrdered] * [SalesOrderLine].[fPricePerUnit]) AS [Value]
FROM [SalesOrderLine]
INNER JOIN [SalesOrder] ON (SalesOrder.iSalesOrderID = SalesOrderLine.iSalesOrderID)
WHERE [SalesOrder].[dOrderDateTime] > DateAdd(month, -12, CURRENT_TIMESTAMP)
GROUP BY sProductSageCode;
SELECT * FROM#Last12MonthsProductSales
ORDER BY CompoundSageCode;
DROP TABLE #Last6WeeksProductSales;
DROP TABLE #Last12MonthsProductSales;
Use a view. That way you don't have to worry about updating your third table, and it will reflect current information. Base the view on a basic SELECT:
SELECT sixS.CompoundSageCode,
(twelveS.value - sixS.Value ) as diffValue
FROM Last6WeeksProductSales sixS
INNER JOIN Last12MonthsProductSales twelveS ON sixS.CompoundSageCode = twelveS.CompoundSageCode
(I have not tested this code, but it should be a good starting point.)
Computing the difference of two tables is usually done using a FULL OUTER JOIN. SQL Server can implement it using all three of the physical join operators. Apply reasonable indexing and it will run fine.
If you can manage it, create covering indexes on both tables that are sorted by the join key. This will result in a highly efficient merge join plan.