TSQL passing 2 values array to stored procedure - tsql

I'm using SQL Server 2012 and C#.
Imagine have something similar to a shopping cart and now need to create an order with the following items:
productA - 4 (qty)
productB - 1 (qty)
productC - 9 (qty)
In my C# code I have a list that looks like this:
id : "productA" , qty : "4"
id : "productB" , qty : "1"
id : "productV" , qty : "9"
Questions:
How can I pass the list of 2 values to the stored procedure?
How can I have the stored procedure run 3 while loops each one running 4 times, then once then 9 times in order to physically create one record x request?
Note: In my case I don't have a QTY column in the table, I need to specifically create one record x item on the order.

You can done this by Table Value Parameter in SQL.
Sql Authority
MSDN
You can done this by passing TVP as #table format
declare #table table(product varchar(10), qty int)
insert into #table
select 'product1', 4 union
select 'product2', 2
;WITH cte AS (
SELECT product, qty FROM #table
UNION ALL
SELECT product, qty-1 FROM cte WHERE qty > 1
)
SELECT t.product, t.qty
FROM cte c
JOIN #table t ON c.product = t.product
ORDER BY 1
Reference for the CTE : Creating duplicate records for a given table row

To pass a table into the stored procedure use table-valued parameter.
At first create a type:
CREATE TYPE [dbo].[ProductsTableType] AS TABLE(
[ID] [varchar](50) NOT NULL,
[qty] [int] NOT NULL
)
Then use this type in the stored procedure. The #ParamProducts is a table and can be used in all queries where a table can be used.
CREATE PROCEDURE [dbo].[AddProducts]
#ParamProducts ProductsTableType READONLY
AS
BEGIN
...
END
To actually insert required number of rows I would use a table of numbers , http://web.archive.org/web/20150411042510/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html
In my database I have a table called Numbers with a column Number that contains numbers from 1 to 100,000. Once you have such table it is trivial to get the set that you need.
DECLARE #T TABLE (ID varchar(50), qty int);
INSERT INTO #T (ID, qty) VALUES ('productA', 4);
INSERT INTO #T (ID, qty) VALUES ('productB', 1);
INSERT INTO #T (ID, qty) VALUES ('productV', 9);
SELECT *
FROM
#T AS Products
INNER JOIN dbo.Numbers ON Products.qty >= dbo.Numbers.Number
;
Result set
ID qty Number
productA 4 1
productA 4 2
productA 4 3
productA 4 4
productB 1 1
productV 9 1
productV 9 2
productV 9 3
productV 9 4
productV 9 5
productV 9 6
productV 9 7
productV 9 8
productV 9 9
This is an example. In your case you would have this SELECT inside INSERT INTO YourFinalTable.

Related

Need to combine the sales of 2 records with different ID's and the record with highest sale id should be in the result set

I have a table with records belonging to same person but the person was assigned with 2 different id's.
I need to combine the sales and then hold on to the id having highest sales.
For Example:
ID Name Sales
1 ABC 10
4 ABC 60
5 xyz 100
6 xyz 10
I need result as
ID Name Sales
4 ABC 70
5 XYZ 110
Please help me with a sql query for the above.
try this:
create table #mytable
(id int,
name nvarchar(20),
Sales int)
insert into #mytable
values
(1,'ABC',10),
(4,'ABC',60),
(5,'xyz',100),
(6,'xyz',10)
select (select top(1) ID
from #mytable r2
where r2.name=r1.name
and r2.Sales=MAX(r1.Sales))as ID,
name,
sum(Sales)
from #mytable r1
group by name
drop table #mytable

Get last row from group, limit number of results in PostgreSQL

I have a table with records representing a log, I omit rest of the columns in this example.
The id-column is autoincrement, item_id represents an item in app.
I need to get the latest item_id, for example two or three
CREATE TABLE "log" (
"id" INT,
"item_id" INT
);
-- TRUNCATE TABLE "log";
INSERT INTO "log" ("id", "item_id") VALUES
(1, 1),
(2, 2),
(3, 1),
(4, 1),
(5, 3),
(6, 3);
Basic query will list all results, latest at the top:
SELECT *
FROM "log"
ORDER BY "id" DESC
id item_id
6 3
5 3
4 1
3 1
2 2
1 1
I would like to have just two (LIMIT 2) last item_ids with their id. Last means - inserted last (ORDER BY id).
id item_id
6 3
4 1
Last three would be
id item_id
6 3
4 1
2 2
Once an item_id is returned, it is not returned again. So LIMIT 4 would return only three rows because there are only three unique item_id.
I am probably missing something. I already tried various combinations of DISTINCT OF, GROUP BY, LIMIT etc.
UPDATE #1:
After I tested query by S-man (below), I found out that it works for the data I provided howerer it does not work in general, for another set of data (sequence of item_id A, B and A again.). Here is another data set:
TRUNCATE TABLE "log";
INSERT INTO "log" ("id", "item_id") VALUES
(1, 1),
(2, 2),
(3, 3),
(4, 3),
(5, 1),
(6, 3);
Data in DB, ordered by id desc:
id item_id
6 3
5 1
4 3
3 3
2 2
1 1
Expected result for last three item_id
6 3
5 1
2 2
Well, after three changes, now we come back to the very first idea:
Just take DISTINCT ON:
demo:db<>fiddle
SELECT
*
FROM (
SELECT DISTINCT ON (item_id) -- 1
*
FROM log
ORDER BY item_id, id DESC
) s
ORDER BY id DESC -- 2
LIMIT 2
Returns exact one record of an ordered group. You group is the item_id, the order is id DESC, so you get the highest id for each item_id
Reorder by id DESC (instead of the previously ordered item_id) and limit your query output.

TSQL, Pivot rows into single columns

Before, I had to solve something similar:
Here was my pivot and flatten for another solution:
I want to do the same thing on the example below but it is slightly different because there are no ranks.
In my previous example, the table looked like this:
LocationID Code Rank
1 123 1
1 124 2
1 138 3
2 999 1
2 888 2
2 938 3
And I was able to use this function to properly get my rows in a single column.
-- Check if tables exist, delete if they do so that you can start fresh.
IF OBJECT_ID('tempdb.dbo.#tbl_Location_Taxonomy_Pivot_Table', 'U') IS NOT NULL
DROP TABLE #tbl_Location_Taxonomy_Pivot_Table;
IF OBJECT_ID('tbl_Location_Taxonomy_NPPES_Flattened', 'U') IS NOT NULL
DROP TABLE tbl_Location_Taxonomy_NPPES_Flattened;
-- Pivot the original table so that you have
SELECT *
INTO #tbl_Location_Taxonomy_Pivot_Table
FROM [MOAD].[dbo].[tbl_Location_Taxonomy_NPPES] tax
PIVOT (MAX(tax.tbl_lkp_Taxonomy_Seq)
FOR tax.Taxonomy_Rank in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15])) AS pvt
-- ORDER BY Location_ID
-- Flatten the tables.
SELECT Location_ID
,max(piv.[1]) as Tax_Seq_1
,max(piv.[2]) as Tax_Seq_2
,max(piv.[3]) as Tax_Seq_3
,max(piv.[4]) as Tax_Seq_4
,max(piv.[5]) as Tax_Seq_5
,max(piv.[6]) as Tax_Seq_6
,max(piv.[7]) as Tax_Seq_7
,max(piv.[8]) as Tax_Seq_8
,max(piv.[9]) as Tax_Seq_9
,max(piv.[10]) as Tax_Seq_10
,max(piv.[11]) as Tax_Seq_11
,max(piv.[12]) as Tax_Seq_12
,max(piv.[13]) as Tax_Seq_13
,max(piv.[14]) as Tax_Seq_14
,max(piv.[15]) as Tax_Seq_15
-- JOIN HERE
INTO tbl_Location_Taxonomy_NPPES_Flattened
FROM #tbl_Location_Taxonomy_Pivot_Table piv
GROUP BY Location_ID
So, then here is the data I would like to work with in this example.
LocationID Foreign Key
2 2
2 670
2 2902
2 5389
3 3
3 722
3 2905
3 5561
So I have some data that is formatted like this:
I have used pivot on data like this before--But the difference was it had a rank also. Is there a way to get my foreign keys to show up in this format using a pivot?
locationID FK1 FK2 FK3 FK4
2 2 670 2902 5389
3 3 722 2905 5561
Another way I'm looking to solve this is like this:
Another way I could look at doing this is I have the values in:
this form as well:
LocationID Address_Seq
2 670, 5389, 2902, 2,
3 722, 5561, 2905, 3
etc
is there anyway I can get this to be the same?
ID Col1 Col2 Col3 Col4
2 670 5389, 2902, 2
This, adding a rank column and reversing the orders, should gives you what you require:
SELECT locationid, [4] col1, [3] col2, [2] col3, [1] col4
FROM
(
SELECT locationid, foreignkey,rank from #Pivot_Table ----- temp table with a rank column
) x
PIVOT (MAX(x.foreignkey)
FOR x.rank in ([4],[3],[2],[1]) ) pvt

Several top numbers in a column T-SQL

I have a table called _Invoice in SQL Server 2016 - like this:
Company InvoiceNo
-----------------
10 1
10 2
10 3
20 1
20 2
20 3
20 4
I want to get the highest value from all companies.
Like this:
Company InvoiceNo
-----------------
10 3
20 3
I want this data to then update another table that is called InvoiceSeries
where the InvoiceNo is higher than the NextNo in InvoiceSeries table
I am stuck with getting the highest data from InvoiceNo:
UPDATE InvoiceSeries
SET NextNo = -- Highest number from each company--
FROM InvoiceSeries ise
JOIN _Invoice i ON ise.InvoiceSeries = i.InvoiceSeries
WHERE i.InvoiceNo > ise.NextNo
Some example data:
Columns in InvoiceSeries Columns in _Invoices
Company NextNo Company InvoiceNo
10 9007 10 9008
20 1001 10 9009
10 9010
10 9011
10 9012
20 1002
20 1003
20 1004
If I understand correctly, you are looking for the HIGHEST common invoice number
Example
Select A.*
From YourTable A
Join (
Select Top 1 with ties
InvoiceNo
From YourTable
Group By InvoiceNo
Having count(Distinct Company) = (Select count(Distinct Company) From YourTable)
Order By InvoiceNo Desc
) B on A.InvoiceNo=B.InvoiceNo
Returns
Company InvoiceNo
10 3
20 3
EDIT - Updated for comment
Select company
,Invoice=max(invoiceno)
From YourTable
Group By company
This answer assumes there will be a record in the Invoice Series table.
--Insert Sample Data
CREATE TABLE #_Invoice (Company INT, InvoiceNo INT)
INSERT INTO #_Invoice(Company, InvoiceNo)
VALUES
(10 , 1),
(10 , 2),
(10 , 3),
(20 , 1),
(20 , 2),
(20 , 3),
(20 , 4)
CREATE TABLE #InvoiceSeries(Company INT, NextNo INT)
INSERT INTO #InvoiceSeries(Company, NextNo)
VALUES
(10, 1),
(20 ,1)
UPDATE s
SET NextNo = MaxInvoiceNo
FROM #InvoiceSeries s
INNER JOIN (
--Get the Max invoice number per company
SELECT Company, MAX(InvoiceNo) as MaxInvoiceNo
FROM #_Invoice
GROUP BY Company
) i on i.Company = s.Company
AND s.NextNo < i.MaxInvoiceNo --Only join to records where the 'nextno' is less than the max
--Confirm results
SELECT * FROM #InvoiceSeries
DROP TABLE #InvoiceSeries
DROP TABLE #_Invoice

How to number rows with a repeating 1,2,3,4, 1,2,3,4,... series

How can I add a series in length of 4 to a table like this:
Source table:
id
1
2
3
4
5
6
7
8
Results table:
id series
1 1
2 2
3 3
4 4
5 1
6 2
7 3
8 4
I'm using PostgreSQL 9.1.
If your IDs are really consecutive and gapless, you can just use id % 4 + 1. But I imagine that in reality your IDs aren't so orderly, and if they're generated from a SEQUENCE you shouldn't rely on them being gapless.
You can do it properly with row_number(), as shown here: http://sqlfiddle.com/#!12/22767/5
SELECT
id,
(row_number() OVER (ORDER BY id) - 1) % 4 + 1
FROM Table1
ORDER BY 1;
It's also possible to do using generate_series as a set-returning-function in the SELECT list, but that's a PostgreSQL extension, wheras the above is standard SQL that'll work in any modern database except MySQL, which doesn't support window functions.
If you want to actually add a column to the table it gets a bit more complicated. I'm not really sure why you'd want to do that, but it's possible using UPDATE ... FROM:
BEGIN;
ALTER TABLE table1 ADD COLUMN col2 INTEGER;
WITH gen_num(id,n) AS (
SELECT
id,
(row_number() OVER (ORDER BY id) - 1) % 4 + 1
FROM Table1
ORDER BY 1)
UPDATE table1 SET col2 = n
FROM gen_num
WHERE gen_num.id = table1.id;
COMMIT;