how to fetch table records and store in variable in sql server and extract each record - sql-server-2008

I have 3 tables
Category(Category_ID,Category_Name,Parent,Category_Tag)
News_Category(ID,News_ID,Category)
News(News_ID,Title,Article,News_Tags)
I want to fetch all Category_Tag from Category Table where News_ID=72. I am using following query in sql server:
DECLARE #cat varchar(100)
SET #cat=(select Category_Tag
from Category
where Category_ID in(
select Category
from News_Category
inner join Category on Category.Category_ID = News_Category.Category
where News_ID=72
)
)
but this query is not working for me it is showing error as:- Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
.Also i want to extract each single record from the above query to update News table column News_Tags.Suppose the News_Tags column in News table contains value "Tejpal" and the above query returning two values- National and Interbational. then the final value should be stored in News_Tags Column of News Table as Tejpal,National,International
Please help me here

The error here is pretty descriptive. You have declared a scalar variable which is designed to hold a single value, and you are trying to insert multiple rows into that variable.
You need to either do one of two things, either use a temporary table such as
DECLARE #Cat TABLE (CategoryTag VARCHAR(1000));
INSERT INTO #Car
SELECT C.Category_Tag
FROM Category C
INNER JOIN News_Category N ON N.Category = C.CategoryID
WHERE N.News_ID = 72
or you can concatenate the values to be a single string.
I think in this case you might be looking for the second option which would look something like this. This code is mostly psuedo taking from another script I have, but it should put you on the right track.
DECLARE #CategoryTags VARCHAR(1000);
SET #CategoryTags = (
SELECT STUFF((
SELECT ISNULL(Category_Tag, 'NullTag')
FROM Category C
INNER JOIN News_Category N ON N.Category = C.CategoryID
WHERE N.News_ID = N1.NewsID
FOR XML PATH (''),TYPE).value('(./text())[1]','VARCHAR (MAX)')
,1,0,'') [Categories]
FROM News_Category N1
WHERE N1.News_ID = 72
UPDATE News_Category
SET NewTags = NewTags + #CategoryTags
WHERE News_ID = 72

This might help you.
DECLARE #combinedString VARCHAR(MAX)
SELECT #combinedString = COALESCE(#combinedString + CHAR(13) + CHAR(10), '') + ISNULL(Category_Tag, 'NullTag')
FROM Category
select #combinedString

Related

How to use variables column name in where clause MySQL?

In this query:
SELECT *
FROM general_settings AS general_settings
JOIN settings_attribute AS settings_attribute ON settings_attribute.id = general_settings.settings_attribute_id
JOIN user_settings AS user_settings ON general_settings.user_settings_id = user_settings.id
WHERE
(settings_attribute.name = 'AAA' AND brand_settings.AAA <> general_settings.value)
OR
(settings_attribute.name = 'BBB' AND brand_settings.BBB <> general_settings.value)
OR
(settings_attribute.name = 'CCC' AND brand_settings.CCC <> general_settings.value)
;
I want a way using MySQL or Redshift to use settings_attribute.name as column name to avoid writing all the attribute names as a static in the query,
for example like this:
SELECT *
FROM general_settings AS general_settings
JOIN settings_attribute AS settings_attribute ON settings_attribute.id = general_settings.settings_attribute_id
JOIN user_settings AS user_settings ON general_settings.user_settings_id = user_settings.id
WHERE
brand_settings.#settings_attribute.name <> general_settings.value
;
No, this is not possible. In SQL, all identifiers (e.g. column names) must be explicit and fixed in the query at the time it is parsed, so the SQL engine can verify that the columns actually exist before it begins executing. It's not possible for a query to name different columns based on the string values it reads during execution.
What would happen if your settings_attribute.name contained 'XYZ' in some row, but there was no column by that name? It would be an error if you named a column that didn't exist, but in SQL that is checked at the time the query is parsed.

Searching for data in SQL

Please take a look at the following table:
I am building a search engine which returns card_id values, based on search of category_id and value_id values.
To better explain the search mechanism, imagine that we are trying to find a car (card_id) by supplying information what part (value_id) the car should has in every category (category_id).
In example, we may want to find a car (card_id), where category "Fuel Type" (category_id) has a value "Diesel" (value_id), and category "Gearbox" (category_id) has a value "Manual" (value_id).
My problem is that my knowledge is not sufficient to build a query, which will returns card_ids which contains more than one pair of category_id and value_id.
For example, if I want to search a car with diesel engine, I could build a query like this:
SELECT card_id FROM cars WHERE category_id=1 AND value_id=2
where category_id = 1 is a category "Fuel Type" and value_id = 2 is "Diesel".
My question is, how can I build a query, which will look for more category-value pairs? For example, I want to look for diesel cars with manual gearbox.
Any help will be very appreciated. Thank you in advance.
You can do this using aggregation and a having clause:
SELECT card_id
FROM cars
GROUP BY card_id
HAVING SUM(category_id = 1 AND value_id = 2) > 0 AND
SUM(category_id = 3 and value_id = 43) > 0;
Each condition in the having clause counts the number of rows that match a given condition. You can add as many conditions as you like. The first, for instance, says that there is at least one row where the category is 1 and the value is 2.
SQL Fiddle
Another approach is to create a user defined function that takes a table of attribute/value pairs and returns a table of matching cars. This has the advantage of allowing an arbitrary number of attribute/value pairs without resorting to dynamic SQL.
--Declare a "sample" table for proof of concept, replace this with your real data table
DECLARE #T TABLE(PID int, Attr Int, Val int)
--Populate the data table
INSERT INTO #T(PID , Attr , Val) VALUES (1,1,1), (1,3,5),(1,7,9),(2,1,2),(2,3,5),(2,7,9),(3,1,1),(3,3,5), (3,7,9)
--Declare this as a User Defined Table Type, the function would take this as an input
DECLARE #C TABLE(Attr Int, Val int)
--This would be populated by the code that calls the function
INSERT INTO #C (Attr , Val) VALUES (1,1),(7,9)
--The function (or stored procedure) body begins here
--Get a list of IDs for which there is not a requested attribute that doesn't have a matching value for that ID
SELECT DISTINCT PID
FROM #T as T
WHERE NOT EXISTS (SELECT C.ATTR FROM #C as C
WHERE NOT EXISTS (SELECT * FROM #T as I
WHERE I.Attr = C.Attr and I.Val = C.Val and I.PID = T.PID ))

Loop through column and update it with MySQL?

I want to loop through some records and update them with an ad hoc query in MySql. I have a name field, so I just want to loop though all of them and append a counter to each name, so it will be name1, name2, name3. Most examples I see use stored procs, but I don't need a stored proc.
As a stepping stone on your way to developing an UPDATE statement, first generate a SELECT statement that generates the new name values to your liking. For example:
SELECT t.id
, t.name
, CONCAT(t.name,s.seq) AS new_name
FROM ( SELECT #i := #i + 1 AS seq
, m.id
FROM mytable m
JOIN (SELECT #i := 0) i
ORDER BY m.id
) s
JOIN mytable t
ON t.id = s.id
ORDER BY t.id
To unpack that a bit... the #i is a MySQL user variable. We use an inline view (aliased as i) to initialize #i to a value of 0. This inline view is joined to the table to be updated, and each row gets assigned an ascending integer value (aliased as seq) 1,2,3...
We also retrieve a primary (or unique) key value, so that we can match each of the rows from the inline view (one-to-one) to the table to be updated.
It's important that you understand how that statement is working, before you attempt writing an UPDATE statement following the same pattern.
We can now use that SELECT statement as an inline view in an UPDATE statement, for example:
UPDATE ( SELECT t.id
, t.name
, CONCAT(t.name,s.seq) AS new_name
FROM ( SELECT #i := #i + 1 AS seq
, m.id
FROM mytable m
JOIN (SELECT #i := 0) i
ORDER BY m.id
) s
JOIN mytable t
ON t.id = s.id
ORDER BY t.id
) r
JOIN mytable u
ON u.id = r.id
SET u.name = r.new_name
SQL Fiddle demonstration here:
http://sqlfiddle.com/#!2/a8796/1
I had to extrapolate, and provide a table name (mytable) and a column name for a primary key column (id).
In the SQL Fiddle, there's a second table, named prodtable which is identical to mytable. SQL Fiddle only allows SELECT in the query pane, so in order to demonstrate BOTH the SELECT and the UPDATE, I needed two identical tables.
CAVEAT: be VERY careful in using MySQL user variables. I typically use them only in SELECT statements, where the behavior is very consistent, with careful coding. With DML statements, it gets more dicey. The behavior may not be as consistent in DML, the "trick" is to use a SELECT statement as an inline view. MySQL (v5.1 and v5.5) will process the query for the inline view and materialize the resultset as a temporary MyISAM table.
I have successfully used this technique to assign values in an UPDATE statement. But (IMPORTANT NOTE) the MySQL documentation does NOT specify that this usage or MySQL user variables is supported, or guaranteed, or that this behavior will not change in a future release.
Have the names stored in a table. Do a join against the names and update in the second table you want to.
Thanks

Get a list of ids not present in a table

I have a list of ids, and I want to query a mysql table for ids not present in the table.
e.g.
list_of_ids = [1,2,4]
mysql table
id
1
3
5
6
..
Query should return [2,4] because those are the ids not in the table
since we cant view ur code i can only work on asumption
Try this anyway
SELECT id FROM list_of_ids
WHERE id NOT IN (SELECT id
FROM table)
I hope this helps
There is a horrible text-based hack:
SELECT
substr(result,2,length(result)-2) AS notmatched
FROM (
SELECT
#set:=replace(#set,concat(',',id,','),',') AS result
FROM (
select #set:=concat(',',
'1,2,4' -- your list here
,',')
) AS setinit,
tablename --Your tablename here
) AS innerview
ORDER BY LENGTH(result)
LIMIT 1;
If you represent your ids as a derived table, then you can do this directly in SQL:
select list.val
from (select 1 as val union all
select 2 union all
select 4
) list left outer join
t
on t.id = list.val
where t.id is null;
SQL doesn't really have a "list" type, so your question is ambiguous. If you mean a comma separated string, then a text hack might work. If you mean a table, then something like this might work. If you are constructing the SQL statement, I would advise you to go down this route, because it should be more efficient.

MySQL sub query select statement inside Update query

I have 2 tables: tbl_taxclasses, tbl_taxclasses_regions
This is a one to many relationship, where the main record ID is classid.
I have a column inside the first table called regionscount
So, I create a Tax Class, in table 1. Then I add regions/states in table 2, assigning the classid to each region.
I perform a SELECT statement to count the regions with that same classid, and then I perform an UPDATE statement on tbl_taxclasses with that number. I update the regionscount column.
This means I'm writing 2 queries. Which is fine, but I was wondering if there was a way to do a SELECT statement inside the UPDATE statement, like this:
UPDATE `tbl_taxclasses` SET `regionscount` = [SELECT COUNT(regionsid) FROM `tbl_taxclasses_regions` WHERE classid = 1] WHERE classid = 1
I'm reaching here, since I'm not sure how robust MySQL is, but I do have the latest version, as of today. (5.5.15)
You could use a non-correlated subquery to do the work for you:
UPDATE
tbl_taxclasses c
INNER JOIN (
SELECT
COUNT(regionsid) AS n
FROM
tbl_taxclasses_regions
GROUP BY
classid
) r USING(classid)
SET
c.regionscount = r.n
WHERE
c.classid = 1
Turns out I was actually guessing right.
This works:
UPDATE `tbl_taxclasses`
SET `regionscount` = (
SELECT COUNT(regionsid) AS `num`
FROM `tbl_taxclasses_regions`
WHERE classid = 1)
WHERE classid = 1 LIMIT 1
I just needed to replace my brackets [] with parenthesis ().