I have an application used for warehousing furniture. If the user enters a line with a qty > 1, I have a simple while loop where the line is broken out to be many unique lines inserted into a SQL db. I.e.
Item chair Qty 3
Becomes
Item |Qty|Unique Key
Chair |1 |1234
Chair |1 |1235
Chair |1 |1236
--
while (Qty >= 1)
{
//Go Get Next Num
// GetNextNum("LN");
int NextNum = GetNextNum("LN"); //Method to get next number from DB table
SqlConnection conn = new SqlConnection();
SqlCommand cmd = new SqlCommand();
string connStr = ConfigurationManager.ConnectionStrings["FurnitureDB"].ConnectionString;
conn.ConnectionString = connStr;
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = conn;
//SQL Parameter List here
cmd.CommandText = "InsertSODtl";
SqlDataReader datareader = cmd.ExecuteReader();
Qty--;
}
My challenge is, there are some items that have a multiplier, where one item will be in 3 pieces. In which case I append a number behind the unique key:
Item Table - Qty 1 - Unique Key
------------------------------------
Table | 1 | 1234
Table | 1 | 12341
Table | 1 | 12342
So I need a nested while loop/for loop or some method to insert the appropriate number of pieces. So a table for example - there could be 2 tables, each with 3 pieces. So I need to
Item Table - Qty 1 - Unique Key
------------------------------------
Table | 1 | 1234
Table | 1 | 12341
Table | 1 | 12342
Table | 1 | 1235
Table | 1 | 12351
Table | 1 | 12352
I'm struggling to come up with the logic to do this correctly.
Thanks for your suggestions.
One option I would look at is doing this all from within the stored procedure to limit the queries you need to execute. This can be really easily achieved using any type of for loop in SQL. Now i have a basic table setup as below.
ItemTable
Item | nvarchar(50)
Qty | int
UniqueKey | int
ItemClassification
Item | nvarchar(50)
NumberOfPieces | int
Then a simple stored procedure such as:
CREATE PROCEDURE [dbo].[InsertSODtl]
#item nvarchar(50),
#uniqueKey int
AS
BEGIN
SET NOCOUNT ON
DECLARE #pieces int = (SELECT TOP 1 NumberOfPieces FROM ItemClassification WHERE Item = #item)
INSERT INTO ItemTable (Item, Quantity, UniqueKey) VALUES (#item, 1, #uniqueKey)
IF #pieces IS NOT NULL AND #pieces > 1
BEGIN
DECLARE #count int = 1;
WHILE #count < #pieces -- < assures we end -1 max piece count
BEGIN
INSERT INTO ItemTable VALUES (#item, 1, CAST(CAST(#uniqueKey as nvarchar(10)) + CAST(#count as nvarchar(5)) as int))
SET #count = #count + 1
END
END
END
Like I said it is pretty basic and probably not exactly how your tables look but the concept is there.
First query the amount of pieces in the ItemClassification table for the Item type (simple string).
Next insert the record into the ItemTable
Finally if #pieces is not null and #pieces > 1 then we run a loop from 1 to #pieces - 1 inserting back into the ItemTable appending the value to the unique key. Now we have to cast the #uniqueKey and #count as string (nvarchar(10)) as we need to concat the values and not add them together.
Again a pretty basic example but limits the required queries.
This also doesnt require a change to your code and can be done in one query.
Example Use:
EXEC InsertSODtl 'Table', 1234
EXEC InsertSODtl 'Table', 1235
EXEC InsertSODtl 'Chair', 1236
Results in:
Related
I need to analyze data from SQL server table. Table contains data connected with qualifications of all employyes in the company and has the following structure (simplified):
| User | Qualification | DateOfQualificationAssignment |
| user000 | Junior | 2014-01-15 |
| user000 | Middle | 2014-02-15 |
| user001 | Middle | 2014-02-02 |
| user001 | Senior | 2014-03-18 |
| user002 | Senior | 2014-02-19 |
| user003 | Junior | 2014-03-04 |
I need the way to determine number of employees having given qualification for the concrete date. It should be some sort of analyze("Qualification", "Date") function returning the folowing for these types of input data:
analyze("Junior", '2014-01-20') - returns 1 (it is user user000)
analyze("Junior", '2014-02-20') - returns 0 (because user000 became Middle on 2014-02-15)
analyze("Middle", '2014-02-25') - returns 2 (because user000 and user001 are having Middle qualification on 2014-02-25)
analyze("Middle", '2014-03-28') - returns 1 (user000 is still Middle, but user001 became Senior on 2014-03-18)
Currently I have no idea how to handle this efficiently. What approach can be used to achieve my goal?
Think this should satisfy your requirements:
create function dbo.analyze(#qualification varchar(50), #date date)
returns int
as
begin
declare #result int;
with cte
as
(
select t.*, rank() over (partition by t.[User] order by t.DateOfQualificationAssignment desc) r
from theTable t -- no clue what the real table is named
where t.DateOfQualificationAssignment < #date
)
select #result = count(*)
from cte
where cte.r = 1 and cte.Qualification = #qualification
return #result;
end
go
Tested with your data:
create table theTable
(
[User] varchar(50) not null,
Qualification varchar(50) not null,
DateOfQualificationAssignment date not null
)
go
insert into theTable([User],Qualification,DateOfQualificationAssignment)
values
('user000','Junior','20140115'),
('user000','Middle','20140215'),
('user001','Middle','20140202'),
('user001','Senior','20140318'),
('user002','Senior','20140219'),
('user003','Junior','20140304')
go
and the results:
select dbo.analyze('Junior','20140120') --returns 1
go
select dbo.analyze('Junior','20140220') --returns 0
go
select dbo.analyze('Middle','20140225') --returns 2
go
select dbo.analyze('Middle','20140328') --returns 1
go
Use row_number() over() in a derived table to enumerate the rows on DateOfQualificationAssignment descending partitioned by User where DateOfQualificationAssignment is less than the date you want to check on.
In the main query you count the rows with the enumerated value 1 and Qualification.
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table T
(
[User] char(7),
Qualification char(6),
DateOfQualificationAssignment date
)
insert into T values
('user000', 'Junior', '2014-01-15'),
('user000', 'Middle', '2014-02-15'),
('user001', 'Middle', '2014-02-02'),
('user001', 'Senior', '2014-03-18'),
('user002', 'Senior', '2014-02-19'),
('user003', 'Junior', '2014-03-04')
Query 1:
declare #Qualification char(6) = 'Middle'
declare #Date date = '2014-03-28'
select count(*)
from (
select T.Qualification,
row_number() over(partition by T.[User] order by T.DateOfQualificationAssignment desc) as rn
from T
where T.DateOfQualificationAssignment < #Date
) as T
where T.rn = 1 and
T.Qualification = #Qualification
Results:
| COLUMN_0 |
|----------|
| 1 |
I have a column of price breaks and need to find the row that contains a certain quantity. It is set up like this:
id | MinimumQuantity | Price
-----------------------------------
1 | 1 | 10
1 | 10 | 20
1 | 25 | 30
...and the quantity could be any number. So, if the quantity is 1 I would need to get the Price 10 (1-10), if the quantity is 15 I would need to get the Price 20 (10-25) and if the quantity is 100 I would need to get Price 30 (25+). So far I have:
select Price from myTable where MinimumQuantity >= #myQuantity and id = #myID
...but of course this doesn't return 25+, it seems like it should be simple but I'm stumped. Thanks for your help.
here is proper query for mysql:
SELECT `Price` from `myTable`
WHERE #myQuantity >= `MinimumQuantity` and `id` = #myID
ORDER BY `MinimumQuantity` ASC
LIMIT 1
for sql server:
SELECT top 1 [Price] from [myTable]
WHERE #myQuantity >= [MinimumQuantity] and [id] = #myID
ORDER BY [MinimumQuantity] ASC
I am getting duplicated data within my GridView, while pulling info from a SQL Server. I am using stored procedures and using some C# to set the parameters then using the SqlDataSource to put the sql data from the stored procedure into a GridView. I have looked at some other problems just like mine, but the SQL scripting was different than mine. I also know that my C# code works just fine, but I will post that also,
Here is the code:
SQL:
SELECT
people.name, comage.age, grad.date
FROM
people
INNER JOIN
(SELECT age, MAX(term)[term]
FROM comage GROUP BY date) comage ON people.term = comage.term
INNER JOIN
(SELECT date, MAX(term)[term]
FROM grad GROUP BY date) grad ON people.term = grad.term
WHERE
people.ID = #ID
ORDER BY
LastName
ASP.net:
<asp:GridView ID="grid" runat="server"></GridView>
C# code:
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "prcedureName";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlParameter param = null;
param = cmd.Parameters.Add("#ID",System.Data.SqlDataType.NChar,255);
param.Direction = System.Data.ParameterDirection.Input;
param.value = in; //in is a string of some value
cmd.Connection = con; //con is a SqlConnection of some sort
SqlDataAdapter adp = new SqlDataAdapter(cmd);
SqlCommandBuilder command = new SqlCommandBuilder(adp);
DataTable data = new DataTable();
data.Locale = System.Globalization.CultureInfo.InvariantCulture;
adp.Fill(data);
grid.DataSource = data;
grid.AutoGenerateColumns = true;
grid.DataBind();
Here are the tables:
people table:
--------------------
|name | ID | term |
--------------------
|jeff | 0 | A |
|Jake | 1 | B |
--------------------
comage table:
--------------------
|Age | Term |
--------------------
|23 | A |
|25 | B |
--------------------
grad table:
--------------------
| Date | Term |
--------------------
| DEC | A |
| SUM | B |
--------------------
Are you sure that you don't have your aggregates backwards in your SQL? I would have expected it to be written more like this:
SELECT people.name, Max(comage.age) age, Max(grad.date) date
FROM people
INNER JOIN comage ON people.term = comage.term
INNER JOIN grad ON people.term = grad.term
WHERE people.ID = #ID
GROUP BY people.name
ORDER BY LastName
Which would produce a result set like this:
name | age | date
------------------
Jeff | 23 | DEC
Jake | 25 | SUM
I only get one record, based on the ID I submitted.
DECLARE #People TABLE ([Name] VARCHAR(10), ID INT, Term VARCHAR(10));
DECLARE #Comage TABLE (Age INT, Term VARCHAR(10));
DECLARE #Grad TABLE ([Date] VARCHAR(10), Term VARCHAR(10));
DECLARE #ID INT;
SET #ID = 0;
INSERT INTO #People VALUES ('Jeff', 0, 'A');
INSERT INTO #People VALUES ('Jake', 1, 'B');
INSERT INTO #Comage VALUES (23, 'A');
INSERT INTO #Comage VALUES (25, 'B');
INSERT INTO #Grad VALUES ('DEC', 'A');
INSERT INTO #Grad VALUES ('SUM', 'B');
SELECT age, MAX(term) [term]
INTO #Comage
FROM #Comage
GROUP BY [Age]
SELECT [Date], MAX(term) [term]
INTO #Grad
FROM #Grad GROUP BY [Date]
SELECT
p.name, c.age, g.[Date]
FROM
#People p
INNER JOIN #Comage c
ON c.term = p.term
INNER JOIN #Grad g
ON g.term = p.term
WHERE
p.ID = #ID
DROP TABLE #Comage
DROP TABLE #Grad
I'm doing a program in C# (windows forms) and SQL-Server where I need to take the strings from two columns and put them into an array. I will use that array later in order to implement autocomplete to some textBoxes. The rules are:
The array should be able to hold whatever the amount of strings I
have in the columns, this amount may exceed 500 strings and is variable.
I will need the distinct values from the columns, no duplicates.
I think I'm supposed to use "UNION" for putting together all the strings from the two columns and SqlDataReader with a "while" cycle when putting the strings into the array.
Here is an example table, use it to explain it to me:
----------------------------
| name | surname |
----------------------------
| John | Jackson |
----------------------------
| Michael | Jones |
----------------------------
| Amanda | Lopez |
----------------------------
| Christina | Lopez |
----------------------------
So how would the query look like and how would can I put the results into an array?
If you want a concatenate use this:
SELECT DISTINCT name + surname FROM MyTable
If you dont want a concatenate you can do this:
SELECT Col1 FROM MyTable
UNION
SELECT Col2 FROM MyTable
A union will work as long as Col1 and Col2 have the same datatype. Once you have the data you can bring it back to the client side (via a sproc) into a dataset, datatable, or sqldatareader.
The rest should be simple, take the data and store it in an array of some sort.
Either through some sort of loop
reader = GetData();
while(reader.read())
{
//store into an array...
}
Copy paste this in sql server management studio
CREATE TABLE #Test
(
col1 varchar(10),
col2 varchar(10)
)
INSERT INTO #Test(col1, col2) VALUES('jon', 'jane')
INSERT INTO #Test(col1, col2) VALUES('jane', 'jane')
INSERT INTO #Test(col1, col2) VALUES('bob', 'phil')
INSERT INTO #Test(col1, col2) VALUES('marc', 'phil')
INSERT INTO #Test(col1, col2) VALUES('jon', 'jon')
INSERT INTO #Test(col1, col2) VALUES('jon', 'Jon')
INSERT INTO #Test(col1, col2) VALUES('jane1', 'jane')
INSERT INTO #Test(col1, col2) VALUES('bob2', 'phil')
INSERT INTO #Test(col1, col2) VALUES('marc2', 'phil')
INSERT INTO #Test(col1, col2) VALUES('ste', 'jane')
SELECT col1 FROM #test
UNION
SELECT col2 FROM #test
DROP TABLE #Test
The result is:
bob
bob2
jane
jane1
jon
marc
marc2
phil
ste
I have a DataTable which is generated from .xls table.
I would like to store this DataTable into an existing table in SQL Server database.
I use SqlBulkCopy to store rows which have unique PK.
Problem is, I also have other rows which have same PK as SQL Server table but contain cells with different value compared to SQL Server table.
In short:
Let's say in my DataTable I have a row like this:
id(PK) | name | number
005 | abc | 123
006 | lge | 122
For my SQL server I have sth like this;
id(PK) | name | number
004 | cbs | 345
005 | lks | 122
Now you see the row 006 can be uploaded straight away into SQL Server using SqlBulkCopy. On the other hand the row 005 can't be inserted using it since SQL server table contains row with identical PK.
Now I tried to manually extract the row. Extract each single cell into an ArrayList then generate an UPDATE Table statement afterwards. However this method seems to be unfeasible as I have so many rows to process.
I am looking for a better method to achieve this goal.
Any help is appreciated.
Thank's
Use the below code:
C# Side code for reading data from DataTable and preparing the XML data:
DataTable dt = new DataTable();
StringBuilder sb = new StringBuilder();
sb.Append("<R>");
for (int i = 0; i < dt.Rows.Count; i++)
{
sb.Append("<C><ID>" + dt.Rows[0].ToString() + "</ID>");
sb.Append("<N>" + dt.Rows[1].ToString() + "</N>");
sb.Append("<I>" + dt.Rows[2].ToString() + "</I></C>");
}
sb.Append("</R>");
///pass XML string to DB side
///
//sb.ToString(); //here u get all data from data table as xml format
Database side Stored Procedure (you will need to update your table name):
CREATE PROCEDURE dbo.UpdateData
-- Add the parameters for the stored procedure here
#data XML
AS
BEGIN
SET NOCOUNT ON;
-- keep data into temp table
create table #tmp_data (id nchar(2),name varchar(20), number int)
DECLARE #XMLDocPointer INT
EXEC sp_xml_preparedocument #XMLDocPointer OUTPUT, #DATA
INSERT INTO #tmp_data(id,name,number)
SELECT ID,N,I
FROM OPENXML(#XMLDocPointer,'/R/C',2)
WITH(
ID nchar(30),
N VARCHAR(20),
I int
)
EXEC sp_xml_removedocument #XMLDocPointer
begin tran
-------------------INSERT not existing ones
INSERT INTO TABLE (id,name,number)
SELECT id,name,number
FROM #tmp_data
WHERE NOT EXISTS
(
SELECT 1
FROM TABLE
WHERE ID = #tmp_data.ID
)
--- update existing ones
UPDATE TABLE
SET name = #tmp_data.name, number = #tmp_data.number
FROM #tmp_data
WHERE #tmp_data.id = TABLE.id
commit tran
if(##error <> 0)
rollback tran
END