I'm converting some data to SQL, and one column is a ID column in the format of last 2 digits of this year, and increment +1 of the last entered row in database.
So this year first entry would be 15-001, the next entry would be 15-002 etc. I cant seem to find an example anywhere online on how to do this? i'm not sure if I could do this in a Computed Column? Using Sql Server 2012.
Thank you!
I highly do not recommend using an ID in the format that you are stating. You will come across many other issues. You can use this code in a stored procedure or function to get next ID value.
DECLARE
#oldID varchar(8),
#newID varchar(8),
#temp varchar(8),
#number decimal,
#day int;
begin
SET #oldID = '15-555'; --select statement for last id
SET #day = YEAR(CURRENT_TIMESTAMP);
IF ( LEN(#oldID) = 6)
SET #temp = SUBSTRING(#oldID, 4, 6);
ELSE
SET #temp = SUBSTRING(#oldID, 3, 5);
SET #number = CAST(#temp AS Decimal(10, 0));
SET #number += 1;
SET #temp = CAST(#number AS varchar(8));
WHILE LEN(#temp) < 3
begin
SET #temp = '0' + #temp;
end
SET #newID = SUBSTRING(CAST(#day AS varchar(8)), 3, 4) + '-' + #temp;
print #newID --ID that you are looking for.
end
Stops working correctly after 15-999 and does not reset to 16-001 if that is what your were asking. Code can be changed to account for these things.
Related
Trying to make a report where employee needs to work 30 working days since last point. I would like to have someway to show anything with 8.0 as working day. So column std_01_04 would show as 12/04/2020 and as a work day.
The sql database has been set up very goofy and having issues pulling from it.
there is a column named yr, data shows the current year "2020"
there is a column named mth_cal, show current month "12" for December.
The tricky part is the day. Column is std_01_15 the last 2 numbers are day of month, this example is the 15th. The data under that column will be a 0 or 8. 8 means they worked(full day) or 0 which means day off/holiday. So I need to pull data from a few spots to make a date and need to figure out 30 working days since last point. Any help would be great.
Edit: This was designed by different company. I have no way of redesigning this. I can only try to work with it. Or I need to go with manually entering all holidays/days off
You can create store procedure or function with input param #year and #month with code below to get all day with 8.0 working hours.
declare #year int = 2020
declare #month int = 11
create table #temp (workingDay date)
declare #index int = 1
declare #query nvarchar(200)
declare #paramdef nvarchar(300) = '#valOut nvarchar(10) OUTPUT'
declare #value nvarchar(10)
while #index <= 30
begin
set #query = 'select #valOut = STD_01_'+ REPLACE(STR(#index, 2), SPACE(1), '0') +' from work where yr='+ CAST(#year as nvarchar(4));
exec sp_executesql #query, #paramdef, #valOut = #value output
if #value = '8.0'
begin
insert into #temp values(CAST(#year as nvarchar(4)) + REPLACE(STR(#month + 1, 2), SPACE(1), '0') + REPLACE(STR(#index, 2), SPACE(1), '0'))
end
set #index = #index + 1
end
select * from #temp
drop table #temp
This is result when i run this code in SQL Server
I think you require results like below. You can use unpivot in sql server.
I have tested with below query.
Create table TestUnpivot(yr int , mnth int, std_01_01 int, std_01_02 int, std_01_03 int, primary key(yr,mnth) )
go
Insert into TestUnpivot values(2019,12,0,8,8),(2020,1,8,0,8),(2020,2,8,8,8)
go
Select * from TestUnpivot
go
Select Yr,Mnth, workd, dayss, Convert(Varchar(2),Mnth)+'/'+right(dayss,2)+'/'+convert(Varchar(4),Yr) as DT
from
(
select * from TestUnpivot
)p
unpivot
(
workd for dayss in (std_01_01,std_01_02,std_01_03)
) as unp
go
This is not a duplicate.
I do understand what the issue means but I don't understand why because the variable contains data. I'm basically trying to make a char(4) column increase alone (just like identity with integers). If the table doesn't contain anything, the first value would be 'C001' otherwise, It simply increase based on the last record.
CREATE PROCEDURE ADD_CL(#nom VARCHAR(20),
#dn DATE)
AS
BEGIN
DECLARE #B CHAR(4)
DECLARE #B_to_int INT
DECLARE #B_new_value CHAR(4)
IF EXISTS(SELECT TOP 1 *
FROM CLIENT)
SET #B_new_value = 'C001'
ELSE
BEGIN
SELECT TOP 1 #B = code_client
FROM client
ORDER BY code_client DESC
SET #B_to_int = CAST(SUBSTRING(#B, 2, 3) AS INTEGER)
SET #B_to_int = #B_to_int + 1;
SET #B_new_value = LEFT(#B, 1) + RIGHT('00' + CAST(#B_to_int AS INT), 3)
END
INSERT INTO CLIENT
VALUES (#B_new_value,
#nom,
#dn)
END
Cannot insert the value NULL into column 'code_client', table 'dbo.CLIENT'; column does not allow nulls. INSERT fails.
#B_new_value represent code_client
Your If Exists should be If Not Exists.
So change
if exists(select TOP 1 * from CLIENT)
to
if not exists(select TOP 1 * from CLIENT)
Also you are adding 00 to your final #B_to_int which is cast as int. so it will show C2,C3 and so on.
If you want to retain the same format, cast it to varchar
SET #B_new_value = LEFT(#B,1) + '00' + CAST(#B_to_int as varchar)
Above line will work only till the count is 9. and then it will continue replicating itself with 1 because 10 will be 0010 and final output will be C0010. To eliminate this issue, use replicate and replicate 0 until 3 characters.
SET #B_new_value = LEFT(#B,1) + REPLICATE('0',3-LEN(#B_to_int)) + #B_to_int
Good Luck.
The other answers already tell you that you should be using NOT EXISTS.
This numbering scheme is quite possibly something you'll regret but you could simplify this a lot as well as making it safer in conditions of concurrency and when you run out of numbers by just doing
CREATE PROCEDURE ADD_CL(#nom VARCHAR(20),
#dn DATE)
AS
BEGIN
DECLARE #B VARCHAR(5);
SET XACT_ABORT ON;
BEGIN TRAN
SELECT #B = FORMAT(1 + RIGHT(ISNULL(MAX(code_client), 'C000'), 3), '\C000')
FROM CLIENT WITH(ROWLOCK, UPDLOCK, HOLDLOCK);
IF ( LEN(#B) > 4 )
THROW 50000, 'Exceeded range',1;
INSERT INTO CLIENT
VALUES (#B,
#nom,
#dn);
COMMIT
END
I believe the following should be 'NOT EXISTS'
if EXISTS(select TOP 1 * from CLIENT)
I have many (>48) columns in one table, each column corresponds to a month and contains sales for that month. I need to create another table in which each column equals the addition of the previous 12 columns, e.g. getting the "rolling year" figure, so that e.g. July 2010 has everything from August 2009 through July 2010 added, August 2010 has everything from September 2009 through August 2010, and so on.
I could write this as:
select
[201007TOTAL] = [200908] + [200909] + ... + [201007]
,[201008TOTAL] = [200909] + ... + [201008]
...
...
into #newtable
from #mytable
I was wondering if there was a smarter way of doing this, either creating these as new columns in the table in one step, or perhaps pivoting the data, doing something to it, and re-pivoting?
Altough everybody is right, a different database set-up would be best, I thought this was a nice problem to play around with. Here's my setup:
CREATE TABLE TEST
(
ID INT
, [201401] decimal(19, 5)
, [201402] decimal(19, 5)
, [201403] decimal(19, 5)
, [201404] decimal(19, 5)
, [201405] decimal(19, 5)
, [201406] decimal(19, 5)
, [201407] decimal(19, 5)
)
INSERT INTO TEST
VALUES (1, 1, 2, 3, 4, 5, 6, 7)
Just one record with data is enough to test.
On the assumption the columns to be summed are consecutive in the table, and the first one is the first with datatype decimal. In other words, the table 'starts' (for want of better word) with a PK, which is usually INT, may be followed by descriptions or whatever, followed by the monthly columns to be summed:
DECLARE #OP_START INT
, #OP_END INT
, #LOOP INT
, #DATE VARCHAR(255)
, #SQL VARCHAR(MAX) = 'SELECT '
, #COLNAME VARCHAR(MAX)
-- Set Date to max date (=columnname)
SET #DATE = '201406'
-- Find Last attribute
SET #OP_END = (
SELECT MAX(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TEST'
AND COLUMN_NAME <= #DATE
)
-- Find First attribute
SET #OP_START = (
SELECT MIN(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TEST'
AND DATA_TYPE = 'DECIMAL'
)
SET #LOOP = #OP_START
-- Loop through the columns
WHILE #LOOP <= #OP_END
BEGIN
SET #COLNAME = (
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TEST'
AND ORDINAL_POSITION = #LOOP
)
-- Build SQL with found ColumnName
SET #SQL = #SQL + '[' + #COLNAME + ']' + '+'
SET #LOOP = #LOOP + 1
END
-- Remove last "+"
SET #SQL = SUBSTRING(#SQL, 1, LEN(#SQL) - 1)
-- Complete SQL
SET #SQL = #SQL + ' FROM TEST'
-- Execute
EXEC(#SQL)
This should keep adding up the monthly values, regardless how many you add. Just change the max date to what pleases you.
I'm NOT saying this is the best way to go, but it is a fun way :P
Ok, I had trouble describing this. I have:
material table (materialID, material, etc...)
ThicknessRange table (ThicknessRangeID, ThicknessRange)
MaterialThicknessRange table (MaterialID, ThicknessRangeID)
I am trying to retrieve all MaterialID's from the MaterialThicknessRange table that fit all required ThicknessRangeID's.
For example, any MaterialID with ThicknessRangeID 1 AND ThicknessRangeID 2, etc with a variable number of ThicknessRangeID's (selected from checkboxes by the user).
Thanks in advance.
Are you guaranteed to have only one entry in the MaterialThicknessRange table for a given Material/ThicknessRange combination?
SELECT MaterialID, COUNT(MaterialID) As NumMaterialThicknesses
FROM MaterialThicknessRange
WHERE ThicknessRangeID IN (1, 2)
GROUP BY MaterialID
HAVING COUNT(MaterialID) > 1
I'm using something like this
select MaterialID from MaterialThicknessRange MTR inner join
dbo.TransformCSVToTable('1,2,15') IDs on MTR.ThiknessRangeID = IDs.ID
where dbo.TransformCSVToTable is a user defined function to transform a csv string to a one column table. Bellow is one sample of such function
ALTER FUNCTION [dbo].[fn_IntegerParameterListFromString]
(
#IntegerParameterList varchar(max)
)
RETURNS #result TABLE (IntegerID int)
AS
begin
declare #temp table (IntegerID int)
declare #s varchar(max), #s1 varchar(10)
declare #len int
set #len =len(#IntegerParameterList)
set #s = #IntegerParameterList
if (right(#s,1)<>',') set #s = #s +','
while #s<>''
begin
set #s1 = substring(#s,1,charindex(',',#s)-1)
if (isnumeric(#s1)= 1)
insert #result (IntegerID) Values ( Cast(#s1 as int))
if (CHARINDEX(',',#s)>0)
begin
set #s = substring (#s, charindex(',',#s)+1, #Len)
end
else
begin
if isnumeric(#s) = 1
insert #result (IntegerID) Values ( Cast(#s as int))
set #s = ''
end
end
return
end
I have a column on a table [SampleTable] called [MyColumn] and i would like the number of time this character appears on the column. The character is ;
Excel has a simple solution for this
=LEN()-LEN(SUBSTITUTE(,";",""))
SELECT LEN(MyColumn) - LEN(REPLACE(MyColumn, ';', ''))
FROM SampleTable
WHERE ...
For best readability in code this is best done with a UDF. For example, the one from here:
CREATE FUNCTION [dbo].[ufn_CountChar] ( #pInput VARCHAR(1000), #pSearchChar CHAR(1) )
RETURNS INT
BEGIN
DECLARE #vInputLength INT
DECLARE #vIndex INT
DECLARE #vCount INT
SET #vCount = 0
SET #vIndex = 1
SET #vInputLength = LEN(#pInput)
WHILE #vIndex <= #vInputLength
BEGIN
IF SUBSTRING(#pInput, #vIndex, 1) = #pSearchChar
SET #vCount = #vCount + 1
SET #vIndex = #vIndex + 1
END
RETURN #vCount
END
GO