I have this code, that works, but I want to insert in the temp table the same values (DateTime and Value) from another variable (UBB_PreT_Line_LA.If_TotalInFeddWeight) present in the same table ([Runtime].[dbo].[History]). Then, I show the result in SQL Report Builder 3.0 in a table.
SET NOCOUNT ON
DECLARE #fechaItem DATETIME;
DECLARE #fechaFinTotal DATETIME;
SET #fechaItem = DateAdd(hh,7,#Fecha)
SET #fechaFinTotal = DateAdd(hh,23,#Fecha)
SET NOCOUNT OFF
DECLARE #tblTotales TABLE
(
VALOR_FECHA DATETIME,
VALOR_VALUE float
)
WHILE #fechaItem < #fechaFinTotal
BEGIN
DECLARE #fechaFin DATETIME;
SET #fechaFin = DATEADD(minute, 15, #fechaItem );
INSERT INTO #tblTotales
SELECT
MAX( [DateTime] ),
MAX( [Value] )
FROM [Runtime].[dbo].[History]
WHERE
[DateTime] >= #fechaItem
AND [DateTime] <= #fechaFin
AND (History.TagName='UBB_PreT_Belt_PF101A.Time_Running')
SET #fechaItem = #fechaFin;
END
SELECT TOP 64 VALOR_FECHA as Fecha,VALOR_VALUE as Valor
FROM #tblTotales
order by Valor ASC
What I want, is to join in a single query the result I get in these two tables, with the same query in which only the variable that is queried changes.
The purpose is to create a unique Dataset in Report Builder to display in a single table, the data of the two tables of the image. The 15 minute interval is because I just want to show the variation of the values every 15 minutes.
enter image description here
I have modified the code (Image_02), and with the Query Designer of the Report Builder I have obtained what is shown in the Image_03. The final goal would be to have the data of the second variable, in two more columns on the right (Fecha_Ton and Valor_Ton). How can I do it?
enter image description here
enter image description here
If I've understood your question correctly, I think that this query replaces your code entirely (and adds the second value):
declare #sample table (Datetime datetime not null, Value int not null,
TagName varchar(50) not null)
insert into #sample (DateTime, Value, TagName) values
('2018-08-16T10:14:00',6,'UBB_PreT_Belt_PF101A.Time_Running'),
('2018-08-16T10:08:00',8,'UBB_PreT_Belt_PF101A.Time_Running'),
('2018-08-16T10:23:00',7,'UBB_PreT_Belt_PF101A.Time_Running'),
('2018-08-16T10:07:00',7,'UBB_PreT_Line_LA.If_TotalInFeddWeight')
declare #Fecha datetime
set #Fecha = '20180816'
select
MAX(DateTime),
MAX(CASE WHEN TagName='UBB_PreT_Line_LA.If_TotalInFeddWeight' THEN Value END) as Fed,
MAX(CASE WHEN TagName='UBB_PreT_Belt_PF101A.Time_Running' THEN Value END) as Running
from
#sample
where
DateTime >= DATEADD(hour,7,#Fecha) and
DateTime < DATEADD(hour,23,#Fecha) and
TagName in ('UBB_PreT_Line_LA.If_TotalInFeddWeight',
'UBB_PreT_Belt_PF101A.Time_Running')
group by DATEADD(minute,((DATEDIFF(minute,0,DateTime)/15)*15),0)
order by MAX(DateTime) asc
Results:
Fed Running
----------------------- ----------- -----------
2018-08-16 10:14:00.000 7 8
2018-08-16 10:23:00.000 NULL 7
(You may want two separate dates following the same pattern using CASE as the values)
You shouldn't be building your data up row by agonising row1, you should find as way (such as that above) to express what the entire result set should look like as a single query. Let SQL Server itself decide whether it's going to do that by searching through the rows in date order, etc.
1There may be circumstances where you end up having to do this, but first exhaust any likely set-based options first.
Related
For example, there is a table
int type
int number
int value
How to make that when inserting a value into a table
indexing started from 1 for different types.
type 1 => number 1,2,3...
type 2 => number 1,2,3...
That is, it will look like this.
type
number
value
1
1
-
1
2
-
1
3
-
2
1
-
1
4
-
2
2
-
3
1
-
6
1
-
1
5
-
2
3
-
6
2
-
Special thanks to #Larnu.
As a result, in my case, the best solution would be to create a table for each type.
As I mentioned in the comments, neither IDENTITY nor SEQUENCE support the use of another column to denote what "identity set" they should use. You can have multiple SEQUENCEs which you could use for a single table, however, this doesn't scale. If you are specific limited to 2 or 3 types, for example, you might choose to create 3 SEQUENCE objects, and then use a stored procedure to handle your INSERT statements. Then, when a user/application wants to INSERT data, they call the procedure and that procedure has logic to use the SEQUENCE based on the value of the parameter for the type column.
As mentioned, however, this doesn't scale well. If you have an undeterminate number of values of type then you can't easily handle getting the right SEQUENCE and handling new values for type would be difficult too. In this case, you would be better off using a IDENTITY and then a VIEW. The VIEW will use ROW_NUMBER to create your identifier, while IDENTITY gives you your always incrementing value.
CREATE TABLE dbo.YourTable (id int IDENTITY(1,1),
[type] int NOT NULL,
number int NULL,
[value] int NOT NULL);
GO
CREATE VIEW dbo.YourTableView AS
SELECT ROW_NUMBER() OVER (PARTITION BY [type] ORDER BY id ASC) AS Identifier,
[type],
number,
[value]
FROM dbo.YourTable;
Then, instead, you query the VIEW, not the TABLE.
If you need consistency of the column (I name identifier) you'll need to also ensure row(s) can't be DELETEd from the table. Most likely by adding an IsDeleted column to the table defined as a bit (with 0 for no deleted, and 1 for deleted), and then you can filter to those rows in the VIEW:
CREATE VIEW dbo.YourTableView AS
WITH CTE AS(
SELECT id,
ROW_NUMBER() OVER (PARTITION BY [type] ORDER BY id ASC) AS Identifier,
[type],
number,
[value],
IsDeleted
FROM dbo.YourTable)
SELECT id,
Identifier,
[type],
number,
[value]
FROM CTE
WHERE IsDeleted = 0;
You could, if you wanted, even handle the DELETEs on the VIEW (the INSERT and UPDATEs would be handled implicitly, as it's an updatable VIEW):
CREATE TRIGGER trg_YourTableView_Delete ON dbo.YourTableView
INSTEAD OF DELETE AS
BEGIN
SET NOCOUNT ON;
UPDATE YT
SET IsDeleted = 1
FROM dbo.YourTable YT
JOIN deleted d ON d.id = YT.id;
END;
GO
db<>fiddle
For completion, if you wanted to use different SEQUENCE object, it would look like this. Notice that this does not scale easily. I have to CREATE a SEQUENCE for every value of Type. As such, for a small, and known, range of values this would be a solution, but if you are going to end up with more value for type or already have a large range, this ends up not being feasible pretty quickly:
CREATE TABLE dbo.YourTable (identifier int NOT NULL,
[type] int NOT NULL,
number int NULL,
[value] int NOT NULL);
CREATE SEQUENCE dbo.YourTable_Type1
START WITH 1 INCREMENT BY 1;
CREATE SEQUENCE dbo.YourTable_Type2
START WITH 1 INCREMENT BY 1;
CREATE SEQUENCE dbo.YourTable_Type3
START WITH 1 INCREMENT BY 1;
GO
CREATE PROC dbo.Insert_YourTable #Type int, #Number int = NULL, #Value int AS
BEGIN
DECLARE #Identifier int;
IF #Type = 1
SELECT #Identifier = NEXT VALUE FOR dbo.YourTable_Type1;
IF #Type = 2
SELECT #Identifier = NEXT VALUE FOR dbo.YourTable_Type2;
IF #Type = 3
SELECT #Identifier = NEXT VALUE FOR dbo.YourTable_Type3;
INSERT INTO dbo.YourTable (identifier,[type],number,[value])
VALUES(#Identifier, #Type, #Number, #Value);
END;
I have a stored procedure in SQL Server that inserts records for actual expenses into a table. When the procedure is invoked the month in question is specified as part of of a variable. For example:
exec dbo.upsert_actuals_load_01_load_data 4
When the code runs it's supposed to insert the records into the column that corresponds to the month. '1' inserts values into jan_amt, '2' inserts values into feb_amt, etc.
I have written this code:
IF #month = 1
INSERT INTO #actuals_b
([forecast_yr_id]
,[entry_type]
,[unit_cd]
,[proj_nbr]
,[jan_amt]
,[feb_amt]
,[mar_amt]
...])
SELECT forecast_yr_id
, entry_type
, unit_cd
, proj_nbr
, month_amt AS jan_amt
, 0 AS feb_amt
, 0 AS mar_amt
....
FROM #actuals;
It seems inefficient to have to write the INSERT INTO statement for each IF #month = condition. Is there a better way to do this?
To expand on my comment, the correct design of your table should be something along the lines of:
--All data types are complete guesses
CREATE TABLE actuals_b ([forecast_yr_id] int,
[entry_type] varchar(10),
[unit_cd] varchar(10),
[proj_nbr] int,
MonthNum int,
Amount decimal(12,2)
...)
Then, instead of an IF...ELSE or CASE expressions, your INSERT becomes a much simpler:
INSERT INTO actuals_b([forecast_yr_id],[entry_type],[unit_cd],[proj_nbr],MonthNum,Amount,...)
SELECT forecast_yr_id,
entry_type,
unit_cd,
proj_nbr,
#month,
month_amt,
...
FROM actuals;
(Note this is pseudo-SQL in the absence of a full table definition).
I agree with Larnu here... but you could build this out dynamically if you use a global temp table in both cases (or real tables)... something like:
declare #column varchar(64) =
case
when #month = 1 then '[jan_amt]'
when #month = 2 then '[feb_amt]'
...
end
create table ##actuals_b (...your table definition...)
declare #sql varchar(max) = '
INSERT INTO ##actuals_b
([forecast_yr_id]
,[entry_type]
,[unit_cd]
,[proj_nbr]
,' + #column = ') select * from ##actuals'
print(#sql)
This assumes ##actuals only has a single amt column, which seems to be the case based off your static values for the other months.
I currently have a stored procedure in MSSQL where I execute a SELECT-statement multiple times based on the variables I give the stored procedure. The stored procedure counts how many results are going to be returned for every filter a user can enable.
The stored procedure isn't the issue, I transformed the select statement from te stored procedure to a regular select statement which looks like:
DECLARE #contentRootId int = 900589
DECLARE #RealtorIdList varchar(2000) = ';880;884;1000;881;885;'
DECLARE #publishSoldOrRentedSinceDate int = 8
DECLARE #isForSale BIT= 1
DECLARE #isForRent BIT= 0
DECLARE #isResidential BIT= 1
--...(another 55 variables)...
--Table to be returned
DECLARE #resultTable TABLE
(
variableName varchar(100),
[value] varchar(200)
)
-- Create table based of inputvariable. Example: turns ';18;118;' to a table containing two ints 18 AND 118
DECLARE #RealtorIdTable table(RealtorId int)
INSERT INTO #RealtorIdTable SELECT * FROM dbo.Split(#RealtorIdList,';') option (maxrecursion 150)
INSERT INTO #resultTable ([value], variableName)
SELECT [Value], VariableName FROM(
Select count(*) as TotalCount,
ISNULL(SUM(CASE WHEN reps.ForRecreation = 1 THEN 1 else 0 end), 0) as ForRecreation,
ISNULL(SUM(CASE WHEN reps.IsQualifiedForSeniors = 1 THEN 1 else 0 end), 0) as IsQualifiedForSeniors,
--...(A whole bunch more SUM(CASE)...
FROM TABLE1 reps
LEFT JOIN temp t on
t.ContentRootID = #contentRootId
AND t.RealEstatePropertyID = reps.ID
WHERE
(EXISTS(select 1 from #RealtorIdTable where RealtorId = reps.RealtorID))
AND (#SelectedGroupIds IS NULL OR EXISTS(select 1 from #SelectedGroupIdtable where GroupId = t.RealEstatePropertyGroupID))
AND (ISNULL(reps.IsForSale,0) = ISNULL(#isForSale,0))
AND (ISNULL(reps.IsForRent, 0) = ISNULL(#isForRent,0))
AND (ISNULL(reps.IsResidential, 0) = ISNULL(#isResidential,0))
AND (ISNULL(reps.IsCommercial, 0) = ISNULL(#isCommercial,0))
AND (ISNULL(reps.IsInvestment, 0) = ISNULL(#isInvestment,0))
AND (ISNULL(reps.IsAgricultural, 0) = ISNULL(#isAgricultural,0))
--...(Around 50 more of these WHERE-statements)...
) as tbl
UNPIVOT (
[Value]
FOR [VariableName] IN(
[TotalCount],
[ForRecreation],
[IsQualifiedForSeniors],
--...(All the other things i selected in above query)...
)
) as d
select * from #resultTable
The combination of a Realtor- and contentID gives me a set default set of X amount of records. When I choose a Combination which gives me ~4600 records, the execution time is around 250ms. When I execute the sattement with a combination that gives me ~600 record, the execution time is about 20ms.
I would like to know why this is happening. I tried removing all SUM(CASE in the select, I tried removing almost everything from the WHERE-clause, and I tried removing the JOIN. But I keep seeing the huge difference between the resultset of 4600 and 600.
Table variables can perform worse when the number of records is large. Consider using a temporary table instead. See When should I use a table variable vs temporary table in sql server?
Also, consider replacing the UNPIVOT by alternative SQL code. Writing your own TSQL code will give you more control and even increase performance. See for example PIVOT, UNPIVOT and performance
I have a table in SQL Server 2008, which has DOB (e.g. 1992-03-15) and in same table, I have an Age column, which is right now Null. I need to update the Age according to the DOB. I have both columns (AGE and DOB) in the same table. I need script which does my job to update Age according to DOB
And other one is in same table, I have Arrival Month (e.g. 8) and Arrival year (e.g. 2011), according to that I need to update another column (Time in country). Say let's say according to example (08(MM), 2011(YYYY)), should update (TimeInCountry) - 4.2 something like that. Which should deduct from current date and time has mentioned into month and year
Do let me know if you need anything else.
Not sure what is the data type your age column is
You can do something like below
Update TableName
Set Age = DATEDIFF(yy, DOB, getdate())
if you using decimal
Age = DATEDIFF(hour,DOB,GETDATE())/8766.0
I believe creating a trigger bill be use full, if you adding new rows in future
For yopur first Problem,
UPDATE TABLE_NAME SET AGE=DATEDIFF(hour,DOB_COLUMN,GETDATE())/8766.0
If you want in Round ,
UPDATE TABLE_NAME SET
AGE= CONVERT(int,ROUND(DATEDIFF(hour,DOB_COLUMN,GETDATE())/8766.0,0))
And Not Sure what you really want to do in the Second Problem,but my guess you can try something like..
Update Table_Name set
TimeInCountry=cast(len(Arrival_year) as varchar(4))+'.'+cast(len(Arrival_Month) as varchar(2))
I have implemented User Defined function
Here it is which may help to someone.
ALTER FUNCTION [dbo].[TimeInCountry]
(
#ArrivalMonth varchar(10),
#ArrivalYear Varchar(10)
) RETURNS VARCHAR(10)
BEGIN
Declare #Ageyear int
Declare #Agemonth int
Declare #Final varchar(10)
Declare #CurrentMonth int
Declare #Currentyear int
Set #CurrentMonth = (Select DatePart(mm, GetDate()))
Set #Currentyear = (Select DatePart(yyyy,GetDate()))
Select #AgeYear = #Currentyear - #ArrivalYear
Select #AgeMonth = #CurrentMonth - #ArrivalMonth
if (#AgeMonth < 0)
BEGIN
Set #AgeYear = #AgeYear - 1
Set #AgeMonth = #AgeMonth + 12
END
Select #Final = (Select Cast(#AgeYear as Varchar(max)) +'.'+ Cast(#AgeMonth as varchar(max)))
Return #Final
---And finally call this function where to update.
--To Check
Select [DBName].TimeInCountry (8,2013)
--- and Finally updating.
Update [DBName].[dbo].[TableName] Set TimeInCountry = dbo.TimeInCountry (ArrivalMonth,ArrivalYear) from [DBName].[dbo].[TableName]
Thanks again everyone.
I want to compare a number of values (up to ten) with a function that will return the smallest value of them.
My colleague wrote the function like:
set #smallest = null
if #smallest is null or #date0 < #smallest
begin
set #smallest = #date0
end
if #smallest is null or #date1 < #smallest
begin
set #smallest = #date1
end
... (repeating 10 times)
Beside of that the if statement could be written smarter (the null check can fall away after the first comparison) I was wondering if creating an in-memory indexed table and let the function return me the first value would be more efficient?
Is there any documentation that I could read for this?
creating an in-memory indexed table
There is no point having an index on 10 records. Create a derived table (will sit in memory) as shown below, then run MIN across the table:
select #smallest = MIN(Adate)
from (
select #date0 Adate union all
select #date1 union all
select #date2 union all
-- ....
select #date9) X