I'm new to SQL Server Management Studio, let's say I have 3 columns in my tbl_product, column1 (nchar(60)), column2 (nchar(60)), and in my column3 I want its value to be the result of (column1 * column2), how can I do that?
I saw a "Formula" in the column properties, but I'm not sure how to set a formula there, here is the screenshot:
Note: let's just set the column1 & column2's datatype to nchar.
Presuming both columns are strings that represent decimals set your Formula to this:
CONVERT(decimal,column1) * CONVERT(decimal,column2)
To change how the column is displayed simply change your SELECT statements. The column data will always be "stored" as accurate as possible.
Try running this:
SELECT CAST(column3 as decimal(10,2)) As ComputedColumn FROM tbl_product
In the above statement the cast means "show me 10 digits in total, and 2 digits after the decimal point". You can change those numbers to whatever you'd like.
You can sum two columns using transact sql while defining your table.
CREATE TABLE dbo.Products
(
ProductID int IDENTITY (1,1) NOT NULL
, QtyAvailable smallint
, UnitPrice money
, InventoryValue AS QtyAvailable * UnitPrice
);
-- Insert values into the table.
INSERT INTO dbo.Products (QtyAvailable, UnitPrice)
VALUES (25, 2.00), (10, 1.5);
-- Display the rows in the table.
SELECT ProductID, QtyAvailable, UnitPrice, InventoryValue
FROM dbo.Products;
Microsoft Docs link for Specify Computed Columns in a Table
CREATE TABLE [dbo].[Test]
( [Test1] [nchar(10)] NULL,
[Test2] [nchar(10)] NULL,
[Total] AS (cast ([a] as int)+ cast( [b] as int))
) ON [PRIMARY]
GO
INSERT INTO dbo.Test ( test1, test2 ) VALUES
( '1', -- test1 - int
'2' -- test2 - int
)
SELECT * FROM dbo.Test
Results:
Test1 test2 total
1 2 3
Related
I am trying to use dataTable.Rows.Count, but sort the result based on a specific parameter.
That parameter being "Column1" in my DataTable. So that the output gives me the rows pertaining to that distinct value only.
My DataTable is in a View, but I need to use the sorted int values in a ViewModel.
I am able to count the rows with public static int o { get; set; } and a
dt.Rows.Count in my DataTable. I then grab the value by instantiating my View in my ViewModel, with int numberOfRows = ViewName.o;.
But that gives me the total number of rows, whereas I need the number of rows per distinct value in "Column1".
My question is, where and how can I do the required sorting?
Because when I've gone as far as to count them and add them to an int (in my ViewModel), there's no way to know what row they used to represent, right?
And If I try to sort in the DataTable (in the View) somehow, I don't know how to reference the distinct values.
They might vary from time to time as the program is used, so I can't hard-code it.
Comment suggested using query instead, adding my stored procedure for help to implement solution:
SET NOCOUNT ON
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[myProcedure]
#param myUserDefinedTableType readonly
AS
BEGIN TRANSACTION
INSERT INTO [dbo].[myTable] (/* list of columns */)
SELECT [Column1], /* this is the column I need to sort by */
-- more columns
-- the rest of the columns
/* I do aggregations to my columns here, I am adding several thousands row to 20 summarized rows, so after this line, I can no longer get ALL the rows per "Column1", but only the summarized rows. How can I count the rows BEFORE I do the aggregations? */
FROM #param
GROUP BY [Column2], [Column1]
ORDER BY [Column2], [Column1]
// Some UPDATE clauses
COMMIT TRANSACTION
I believe the wisest choice is to act in the db side.
Assuming you're using SQL Server, the query should be:
SELECT *, COUNT(*) OVER (PARTITION BY Column1) AS c
FROM Table1
ORDER BY c
This query returns the data on your table "Table1", plus the column "c" that represents the count of the value of "Column1", per each row.
Finally, it sorts rows by the column "c", as you request.
EDIT
To complete this task, I will use a Common Table Expression:
-- Code before INSERT...
;WITH CTE1 AS (
SELECT *,
COUNT(*) OVER (PARTITION BY [Column1]) AS c
FROM #param
)
INSERT INTO [dbo].[myTable] (/* list of columns - must add the column c */)
SELECT [Column1],
[Column2],
[c],
-- aggregated columns
FROM CTE1
GROUP BY [Column2], [Column1], c
-- Code after INSERT...
In the Common Table Expression "CTE1" I select all the values in #param, adding a column "c" with the count per Column1.
Note: if you have 5 rows with the same value of Column1, but two different values in Column2, in myTable you will have two rows (because of the GROUP BY [Column2], [Column1]), both with c=5.
If you want instead obtain the count grouped by Column1 and Column2, you have to declare c as follows: COUNT(*) OVER (PARTITION BY [Column1], [Column2]) AS c.
I hope I was clear, If not I'm available to explain it in a different way.
EXAMPLE
CREATE TABLE myTable (col1 VARCHAR(50), col2 INT, col3 INT, c INT)
CREATE TYPE myUserDefinedTableType AS TABLE (column1 VARCHAR(50), column2 INT, column3 INT)
DECLARE #param myUserDefinedTableType
INSERT INTO #param VALUES ('A', 1, 4), ('A', 2, 3), ('A', 2, 6), ('B', 2, 3)
;WITH CTE1 AS (
SELECT *, COUNT(*) OVER (PARTITION BY [Column1]) AS c
FROM #param
)
INSERT INTO [myTable]([col1], [col2], [col3], [c])
SELECT [column1], [column2],
-- aggregated columns
MAX([column3]),
-- count
[c]
FROM CTE1
GROUP BY [column2], [column1], c
DataView dv = dt.DefaultView;
dv.Sort = "SName ASC"; -- your column name
DataTable dtsorted = dv.ToTable();
DataTable dtsorted = dv.ToTable(true, "Sname","Surl" ); //return distinct rows
I have a table bawe_services. i want to fetch all data that match with given keys
like i have fields
id | Service_id |bawe_id
1 2 2
2 3 3
3 2 3
if i pass service =2 i need all record of service_id=2 if i pass service=1,2,3 than i want 0 rows because 1 service is not given by any bawe so. i got 0 rows.
I use this query
select * from aspnet_bawe_services where ser_id in(1,2,3)
Thanx in advance
The count of the parameters in the "in" statement must match the having equal number.
select bawe_id from [dbo].[aspnet_bawe_services]
where Service_id in (2)
group by bawe_id
having count(Service_id)=1;
bawe_id
-----------
2
3
select bawe_id from [dbo].[aspnet_bawe_services]
where Service_id in (2,3)
group by bawe_id
having count(Service_id)=2;
bawe_id
-----------
3
select bawe_id from [dbo].[aspnet_bawe_services]
where Service_id in (1,2,3)
group by bawe_id
having count(Service_id)=3;
bawe_id
-----------
(0 row(s) affected)
TRY THIS: It's really tedious but unique requirement and I think to accomplish this, we have to use function
1-Function returns distinct count of service_id
2-Function to split comma separated value and return in table format
--Function returns distinct count of service_id
CREATE FUNCTION [dbo].[getCount](#service_id varchar(500))
RETURNS INT
AS
BEGIN
DECLARE #count int
SELECT #count = COUNT(DISTINCT(t.service_id))
FROM tmptos t
INNER JOIN [dbo].[SplitValue](#service_id, ',') tt on t.service_id = tt.items
RETURN #count
END;
--Function to split comma separated value and return in table format
--Function copied from
--separate comma separated values and store in table in sql server
CREATE FUNCTION [dbo].[SplitValue](#String varchar(MAX), #Delimiter char(1))
RETURNS #temptable TABLE (items VARCHAR(MAX))
AS
BEGIN
DECLARE #idx int
DECLARE #slice varchar(8000)
SELECT #idx = 1
if len(#String)<1 or #String is null return
WHILE #idx!= 0
BEGIN
set #idx = charindex(#Delimiter,#String)
IF #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
IF(LEN(#slice)>0)
INSERT INTO #temptable(Items) values(#slice)
SET #String = right(#String,len(#String) - #idx)
IF LEN(#String) = 0 break
END
RETURN
END;
--Table with Sample Data
create table tmptos(id int, Service_id int, bawe_id int)
insert into tmptos values
(1, 2, 2),
(2, 3, 3),
(3, 2, 3)
declare #service_id varchar(50) = '2,3'
select *
from tmptos t
inner join [dbo].[SplitValue](#service_id, ',') tt on t.Service_id = tt.items
where [dbo].[getCount](#service_id) = (select count(distinct(items)) from [dbo].[SplitValue](#service_id, ','))
OUTPUT:
id Service_id bawe_id items
1 2 2 2
2 3 3 3
3 2 3 2
It's bit lengthy but works perfectly.
select * from aspnet_bawe_services
where Service_id in (1,2,3)
and
( select count(distinct Service_id) from aspnet_bawe_services where Service_id in (1,2,3) ) = 3
last number in query (in this case "3") is elements count, which you have in IN list.
You can get the service ids that you want using group by and having:
select service_id
from t
where bawe_id in (1, 2, 3)
group by service_id
having count(distinct bawe_id) = 3;
The "= 3" is the number of ids in the IN list.
You can then use in or join or exists to get the full records:
select t.*
from t
where t.service_id in (select service_id
from t
where bawe_id in (1, 2, 3)
group by service_id
having count(distinct bawe_id) = 3
);
Suppose that I have table that holds some data for individuals and companies, and I want to retrieve default value if no data found for individuals or companies, for example, suppose that I have a table
CustomerAccountId CustomerAccountType DueDays IsAdjustable isDefaultForIndividual isDefaultForCompany
1 Individual 10 true false false
2 Company 20 false false false
null null 5 false true false
null null 30 true false true
I want to create a function that takes two parameters IndividualCustomerAccountId and CompanyCustomerAccountId if IndividualCustomerAccountId found in the table retrieve it, if not found retrieve the default value for individuals which is the third row in this case , the same for companies, if theCompanyCustomerAccountIdis found retrieve it, if not get the default value for the companies which isfourth row` in this case.
suppose that we created a funtion which accepts IndividualCustomerAccountId as the first parameter and CompanyCustomerAccountId as the second parameter
sample input
MyFunc(1 , 2) should return first and second rows
MyFunc(1 , 50) should return first and fourth rows because no company with CustomerAccountId 50 found in the table so retrieve the default value for companies which is the fourth row
MyFunc(100 , 2) should return second and third rows because no individual with customer account Id 100 is found so we get the default value for individuals which is the third row, and we have a company with customerAccountId 2, so we simply can retrive it from the table.
I want to create either a LINQ query or SQL function to achieve these results
You could try SQL function
CREATE TABLE Customer
(
CustomerAccountId int,
CustomerAccountType varchar(20),
DueDays int,
IsAdjustable bit,
isDefaultForIndividual bit,
isDefaultForCompany bit
)
INSERT INTO Customer VALUES
(1, 'Individual', 10, 1,0,0),
(2, 'Company', 20, 0,0,0),
(null, null, 5, 0,1,0),
(null, null, 30, 1,0,1)
GO
CREATE FUNCTION MyFunc
(
#IndividualCustomerAccountId int,
#CompanyCustomerAccountId int
)
RETURNs #result TABLE
(
CustomerAccountId int,
CustomerAccountType varchar(20),
DueDays int,
IsAdjustable bit,
isDefaultForIndividual bit,
isDefaultForCompany bit
)
BEGIN
INSERT INTO #result
SELECT CustomerAccountId , CustomerAccountType, DueDays, IsAdjustable, isDefaultForIndividual,isDefaultForCompany
FROM Customer c
WHERE (CustomerAccountId = #IndividualCustomerAccountId AND CustomerAccountType = 'Individual')
OR (CustomerAccountId = #CompanyCustomerAccountId AND CustomerAccountType = 'Company')
IF(NOT EXISTS (SELECT 1 FROM Customer c
WHERE CustomerAccountId = #IndividualCustomerAccountId AND CustomerAccountType = 'Individual' ))
BEGIN
INSERT INTO #result
SELECT CustomerAccountId , CustomerAccountType, DueDays, IsAdjustable, isDefaultForIndividual,isDefaultForCompany
FROM Customer c
WHERE CustomerAccountId IS NULL AND isDefaultForIndividual = 1
END
IF(NOT EXISTS (SELECT 1 FROM Customer c
WHERE CustomerAccountId = #CompanyCustomerAccountId AND CustomerAccountType = 'Company' ))
BEGIN
INSERT INTO #result
SELECT CustomerAccountId , CustomerAccountType, DueDays, IsAdjustable, isDefaultForIndividual,isDefaultForCompany
FROM Customer c
WHERE CustomerAccountId IS NULL AND isDefaultForCompany = 1
END
RETURN;
END
GO
SELECT * from dbo.MyFunc(1,2)
SELECT * from dbo.MyFunc(1,50)
SELECT * from dbo.MyFunc(100,2)
SELECT * from dbo.MyFunc(100,50)
--DROP TABLE Customer
Demo link: Rextester
Basically, you can run an IF Exists with your query to see if there is going to be any data. If so, go ahead and run your query. If not, do a select default row.
If Exists (your query)
(your query)
Else
SELECT 'query for default row'
I hope its clear your problem.
Happy Coding.Thanks
I have a table structure like that as shown below. I want to show names under parent of names (where parent is ledger group)
DECLARE #t1 TABLE
(
ParentGroup varchar(20),
LedgerName varchar(20),
TotalDebit float,
credit float
)
INSERT INTO #t1
SELECT *
FROM Table1
INSERT INTO #t1
SELECT Distinct ParentGroup, ParentGroup, NULL, NULL
FROM Table1
Select LedgerName, TotalDebit, credit from #t1
group by LedgerName, TotalDebit, credit
ORDER BY (CASE WHEN TotalDebit IS NULL THEN 0 ELSE TotalDebit END)
I want to let a user search through all the columns in a table for a set of phrases defined in a textbox (split terms with whitespace).
So what first came to mind is finding a way in SQL to concatenate all the columns and just use the LIKE operator (for each phrase) in this result.
The other solution I thought of is writing an algorithm which takes all the phrases searched, and match them with all the columns.
So I ended up with the following:
String [] columns = {"col1", "col2", "col3", "col4"};
String [] phrases = textBox.Text.Split(' ');
I then took all the possible combinations of columns and phrases, and put that into a where-clause-format for sql and then the result was
"(col1 LIKE '%prase1%' AND col1 LIKE '%phrase2%') OR
(col1 LIKE '%phrase1%' AND col2 LIKE '%phrase2%') OR
(col1 LIKE '%phrase2%' AND col2 LIKE '%phrase1%') OR
(col2 LIKE '%phrase1%' AND col3 LIKE '%phrase2%')"
The above is just an example snippet of the output, the amount of conditions being created in this algorith is measured by
conditions=columns^(phrases+1)
So I observed that having 2 search phrases can still give good performance, but more than that will certainly decrease performance drastically.
What is the best practise when searching all the columns for the same data?
Edwin,
I didn't know you was using ORACLE. My solution is using SQL Server. Hopefully you will get the gist of the solution and translate into PL/SQL.
Hopefully this is useful to you.
I am manually populating the #search temp table. You will need to somehow do that. Or look for some Split Function that will take the delimited string and return a Table.
IF OBJECT_ID('tempdb..#keywords') IS NOT NULL
DROP TABLE #keywords;
IF OBJECT_ID('tempdb..#search') IS NOT NULL
DROP TABLE #search;
DECLARE #search_count INT
-- Populate # search with all my search strings
SELECT *
INTO #search
FROM (
SELECT '%ST%' AS Search
UNION ALL
SELECT '%CL%'
) T1
SELECT #search_count = COUNT(*)
FROM #search;
PRINT #search_count
-- Populate my #keywords table with all column values from my table with table id and values
-- I just did a select id, value union with all fields
SELECT *
INTO #keywords
FROM (
SELECT client_id AS id
,First_name AS keyword
FROM [CLIENT]
UNION
SELECT client_id
,last_name
FROM [CLIENT]
) AS T1
-- see what is in there
SELECT *
FROM #search
SELECT *
FROM #keywords
-- I am doing a count(distinct #search.Search). This will get me a count,
--so if I put in 3 search values my count should equal 3 and that tells me all search strings have been found
SELECT #keywords.id
,COUNT(DISTINCT #search.Search)
FROM #keywords
INNER JOIN #search ON #keywords.keyword LIKE #search.Search
GROUP BY #keywords.id
HAVING COUNT(DISTINCT #search.Search) = #search_count
SELECT *
FROM [CLIENT]
WHERE [CLIENT].client_id IN (
SELECT #keywords.id
FROM #keywords
INNER JOIN #search ON #keywords.keyword LIKE #search.Search
GROUP BY #keywords.id
HAVING COUNT(DISTINCT #search.Search) = #search_count
)
You could create a stored procedure or function in PL/SQL to dynamically search the table for the search terms and then bring back the primary key and column of any matches. The code sample below should be enough to tailor to your requirements.
create table text_table(
col1 varchar2(32),
col2 varchar2(32),
col3 varchar2(32),
col4 varchar2(32),
col5 varchar2(32),
pk varchar2(32)
);
insert into text_table(col1, col2, col3, col4, col5, pk)
values ('the','quick','brown','fox','jumped', '1');
insert into text_table(col1, col2, col3, col4, col5, pk)
values ('over','the','lazy','dog','!', '2');
commit;
declare
rc sys_refcursor;
cursor_num number;
col_count number;
desc_tab dbms_sql.desc_tab;
vs_column_value varchar2(4000);
search_terms dbms_sql.varchar2a;
matching_cols dbms_sql.varchar2a;
empty dbms_sql.varchar2a;
key_value varchar2(32);
begin
--words to search for (i.e. from the text box)
search_terms(1) := 'fox';
search_terms(2) := 'box';
open rc for select * from text_table;
--Get the cursor number
cursor_num := dbms_sql.to_cursor_number(rc);
--Get the column definitions
dbms_sql.describe_columns(cursor_num, col_count, desc_tab);
--You must define the columns first
for i in 1..col_count loop
dbms_sql.define_column(cursor_num, i, vs_column_value, 4000);
end loop;
--loop through the rows
while ( dbms_sql.fetch_rows(cursor_num) > 0 ) loop
matching_cols := empty;
for i in 1 .. col_count loop --loop across the cols
--Get the column value
dbms_sql.column_value(cursor_num, i, vs_column_value);
--Get the value of the primary key based on the column name
if (desc_tab(i).col_name = 'PK') then
key_value := vs_column_value;
end if;
--Scan the search terms array for a match
for j in 1..search_terms.count loop
if (search_terms(j) like '%'||vs_column_value||'%') then
matching_cols(nvl(matching_cols.last,0) + 1) := desc_tab(i).col_name;
end if;
end loop;
end loop;
--Print the result matches
if matching_cols.last is not null then
for i in 1..matching_cols.last loop
dbms_output.put_line('Primary Key: '|| key_value||'. Matching Column: '||matching_cols(i));
end loop;
end if;
end loop;
end;