mssql, asp.net, I need to deliver table, without records associated with specific ID - asp.net

Imagine, that I need to retrieve all records excluding, those, that are associated
with specific ID, for instance if you consider table below and chose RestaurantID 1, resulting table should not include rows, that contain CuisineID 3,4 and 7.
If RestaurantID is 6, then resulting table should return anything without CuisineID 1 and 8
and so on
My table
Kind regards
erwre

if you do a subselect with your query, you can get a list of which CuisineID's to exclude using the NOT IN clause.
select
t.*
from
mytable t
where
t.CuisineID NOT IN
(
select
t2.CuisineID
from
mytable t2
where
t2.ID = #YOUR_RESTAURANT_ID
)

Related

"Insert if not exists" statement in SQLite

I have an SQLite database. I am trying to insert values (users_id, lessoninfo_id) in table bookmarks, only if both do not exist before in a row.
INSERT INTO bookmarks(users_id,lessoninfo_id)
VALUES(
(SELECT _id FROM Users WHERE User='"+$('#user_lesson').html()+"'),
(SELECT _id FROM lessoninfo
WHERE Lesson="+lesson_no+" AND cast(starttime AS int)="+Math.floor(result_set.rows.item(markerCount-1).starttime)+")
WHERE NOT EXISTS (
SELECT users_id,lessoninfo_id from bookmarks
WHERE users_id=(SELECT _id FROM Users
WHERE User='"+$('#user_lesson').html()+"') AND lessoninfo_id=(
SELECT _id FROM lessoninfo
WHERE Lesson="+lesson_no+")))
This gives an error saying:
db error near where syntax.
If you never want to have duplicates, you should declare this as a table constraint:
CREATE TABLE bookmarks(
users_id INTEGER,
lessoninfo_id INTEGER,
UNIQUE(users_id, lessoninfo_id)
);
(A primary key over both columns would have the same effect.)
It is then possible to tell the database that you want to silently ignore records that would violate such a constraint:
INSERT OR IGNORE INTO bookmarks(users_id, lessoninfo_id) VALUES(123, 456)
If you have a table called memos that has two columns id and text you should be able to do like this:
INSERT INTO memos(id,text)
SELECT 5, 'text to insert'
WHERE NOT EXISTS(SELECT 1 FROM memos WHERE id = 5 AND text = 'text to insert');
If a record already contains a row where text is equal to 'text to insert' and id is equal to 5, then the insert operation will be ignored.
I don't know if this will work for your particular query, but perhaps it give you a hint on how to proceed.
I would advice that you instead design your table so that no duplicates are allowed as explained in #CLs answer below.
For a unique column, use this:
INSERT OR REPLACE INTO tableName (...) values(...);
For more information, see: sqlite.org/lang_insert
insert into bookmarks (users_id, lessoninfo_id)
select 1, 167
EXCEPT
select user_id, lessoninfo_id
from bookmarks
where user_id=1
and lessoninfo_id=167;
This is the fastest way.
For some other SQL engines, you can use a Dummy table containing 1 record.
e.g:
select 1, 167 from ONE_RECORD_DUMMY_TABLE

Creating a VIEW from multiple tables each with a different number of columns

I want to combine multiple tables into one VIEW.
My understanding is that if the number of columns are different we cannot use UNION.
How do I solve this?
I have the following three TABLES:
1.Table Name- Albums
2.Table Name-AlbumPictures
3.Table Name-Stories
I want to have 3 tables as follows:(i can do this part using INNER JOINS- kindly correct me if i am wrong)
For Stories: StoryID,AlbumID,StoryTitle,AlbumCover,Votes
For Albums: AlbumID,AlbumName,AlbumCover,Votes
For Pictures: AlbumPictureID,Votes
I want to merge all the rows retrieved from the above queries into one VIEWand shuffle them. As the number of columns are different in each of the result sets above am I able to combine them into one VIEW?
So in your UNION sql, either remove the extra columns from the sql for the table with too many, or add extra columns with constant default values to the sql for the table with fewer columns.
Based on your example output, adding extra constant values might look like this...
Select StoryID id, AlbumID,
StoryTitle name, AlbumCover, Votes
From Stories
UNION
Select AlbumID id, AlbumID,
AlbumName name, AlbumCover, Votes
From Albums
UNION
Select AlbumPictureID id, null AlbumId,
null AlbumCover, Votes
From pictures
Order By id, Votes, name
But this makes me want to ask WHY???
EDIT: To sort, just add an order by using output column names, as shown above....
In order to use a UNION or UNION ALL operator, the number of columns and datatypes of the columns returned by each query have to be the same.
One trick you can use is to return a NULL value for the columns that are "missing" from some of the queries.
For performance, I recommend you use the UNION ALL operator in place of the UNION operator, if removing duplicates is not a requirement.
Whenever I need to do something like this, I usually include a literal in each query, as an identifier of which query the row came from.
e.g.
SELECT 'a' AS source
, a.id AS id
, a.name AS name
FROM table_a a
UNION ALL
SELECT 'b' AS source
, b.id AS id
, NULL AS name
FROM table_b b
ORDER BY 1,2
You can do something like this. All three tables are given similar columns with null values and TableName column is to identify the table which brings the data
EDIT: I have to say, this is not the right approach. I wanted to show you how to union tables but I think now it is getting ugly when editing it according to your comments.
--Note: Vote is on all three table, I have selected from Stories
select s.storyId, a.albumId, s.storyTitle, null albumName,
ap.albumCover, s.votes , null albumPictureId, 'stories-albums-albumPics' tableName
from Stories s join Albums a on s.albumId = a.albumId
join AlbumPictures ap on a.albumid = ap.albumId
UNION ALL
select null storyId, a.albumID, null storyTitle, a.albumName,
ap.albumCover, a.votes, null albumPictureId, 'albums-albumPics' tableName
from Albums a join AlbumPictures ap on a.albumid = ap.albumId
UNION ALL --use required table here as well
select null storyId, null albumId, null storyTitle, null albumName,
null albumCover, votes, albumPictureId, 'pictures' tableName
from Pictures
I guess this makes little sense,
Select StoryID+'SID' id, AlbumID,
StoryTitle name, AlbumCover, Votes
From Stories
UNION
Select AlbumID+'AID' id, AlbumID,
AlbumName name, AlbumCover, Votes
From Albums
UNION
Select AlbumPictureID+'APID' id, null AlbumId,
null AlbumCover, Votes
From pictures
Concatenating 'SID','AID' and 'APID' and it will make some sense when you see UI data
select * from Stories as s
inner join Albums as a on a.AccountID = s.AccountID
inner join Pictures as p on p.AccountID = s.AccountID
will return all, as long as AccountID is defined in all 3 tables
To only obtain the unique columns change * for the columns you desire
Why on earth would you need the data to be all in the same view? Just return 3 sets of data. If for example you are using a web browser as the front end, you could perform three queries and return them as a single set of JSON, for example:
{
Albums: [
{AlbumID: 1, AlbumName: 'blah', ... },
{AlbumID: 2, AlbumName: 'gorp', ... }
],
AlbumPictures: [
{AlbumID: 1, URL: 'http://fun.jpg'},
{AlbumID: 1, URL: 'http://fun2.jpg'}
],
Stories [
{StoryID: 3, StoryTitle: 'Jack & Jill', ... },
{ etc. }
]
}
There is absolutely no programming architectural constraint forcing you to put everything together in a single view.

Is it possible to use WHERE clause in same query as PARTITION BY?

I need to write SQL that keeps only the minimum 5 records per each identifiable record in a table. For this, I use partition by and delete all records where the value returned is greater than 5. When I attempt to use the WHERE clause in the same query as the partition by statement, I get the error "Ordered Analytical Functions not allowed in WHERE Clause". So, in order to get it to work, I have to use three subqueries. My SQL looks ilke this:
delete mydb.mytable where (field1,field2) in
(
select field1,field2 from
(
select field1,field2,
Rank() over
(
partition BY field1
order by field1,field2
) n
from mydb.mytable
) x
where n > 5
)
The innermost subquery just returns the raw data. Since I can't use WHERE there, I wrapped it with a subquery, the purpose of which is to 1) use WHERE to get records greater than 5 in rank and 2) select only field1 and field2. The reason why I select only those two fields is so that I can use the IN statement for deleting those records in the outermost query.
It works, but it appears a bit cumbersome. I'd like to consolidate the inner two subqueries into a single subquery. Is this possible?
Sounds like you need to use the QUALIFY clause which is the HAVING clause for Window Aggregate functions. Below is my take on what you are trying to accomplish.
Please do not run this SQL directly against your production data without first testing it.
/* Physical Delete */
DELETE TGT
FROM MyDB.MyTable TGT
INNER JOIN
(SELECT Field1
, Field2
FROM MyDB.MyTable
QUALIFY ROW_NUMBER() (PARTITION BY Field1, ORDER BY Field1,2)
> 5
) SRC
ON TGT.Field1 = SRC.Field1
AND TGT.Field2 = SRC.Fileld2
/* Logical Delete */
UPDATE TGT
FROM MyDB.MyTable TGT
,
(SELECT Field1
, Field2
FROM MyDB.MyTable
QUALIFY ROW_NUMBER() (PARTITION BY Field1, ORDER BY Field1,2)
> 5
) SRC
SET Deleted = 'Y'
/* RecordExpireDate = Date - 1 */
WHERE TGT.Field1 = SRC.Field1
AND TGT.Field2 = SRC.Fileld2

Sqlite Query replacing a column with a column from another table

I have 2 tables, one is indexing the other.
I am querying Table#1, and it has one column (string) that has an ID in it that corresponds to a unique row in Table#2. Im trying to write a query in Sqlite that allows me to retrieve the value from Table#2 if the column value in Table#1 is not an empty string.
Kinda like:
"SELECT TMake,TModel,TTrim,IYear,[%q] AS TPart1 FROM AppGuide WHERE TPart1 != ''"
But instead of retrieving the Index value (TPart1) Id like to get the string from Table#2.
Is this possible?
Any help is appreciated.
You could use a correlated subquery:
SELECT TMake,
TModel,
...,
(SELECT stringvalue
FROM Table2
WHERE Table2.ID = Table1.TPart1)
FROM Table1
WHERE Table1.TPart1 != ''
However, these are rather slow to execute, so you'd better use a join (this returns exactly the same result):
SELECT Table1.TMake,
Table1.TModel,
...,
Table2.stringvalue
FROM Table1 LEFT JOIN Table2 ON Table1.TPart1 = Table2.ID
WHERE Table1.TPart1 != ''
If you don't want to get records from Table1 that have no matching Table2 record, drop the LEFT.

SQL Server: How to select multiple columns with 1 column being distinct?

I am trying to do an SQL query on two tables to retrieve multiple columns with a certain column (PostID) to be distinct (and it is not the primary key of the that table).
In addition, I need the selected distinct rows to be the latest (one of the columns retrieved is the entry date).
Detailed description:
I am building a forum like application, using 3 tables to store data.
I use table1 to store user details, table2 to store the meta data for posts, table3 to store the post details, updates, and replies (postID is unique in table2 pointing towards an original post, while in table3, it is used to show the original post and updates and replies).
Table columns:
table1 (UserID, FullName, mobile, etc.)
table2 (postID, UserID, EntryDate, Deleted columns)
table3 (postdetailsId, PostID, UserID, Entrydate, etc.)
I am trying to retrieve all the posts for 1 user in a gridview, my SQL query uses the USERID to retrieve all his posts from the table. However, it is retrieving the original post and all its updates, and I only want to retrieve the latest update of each post.
How can it be done fully in SQL (I know I can do it in C# with the returned results)?
My query:
SELECT T1.FullName, T3.PostID, T3.EntryDate, T3.Title
FROM Table1 as T1, Table3 as T3
WHERE T3.UserID = T1.UserID
AND T3.UserID = #UserID
You could use GROUP BY PostID along with MAX(EntryDate)
SELECT *
FROM (
SELECT posts.*, ROW_NUMBER() OVER (PARTITION BY post_updates.UserID, post_updates.PostID ORDER BY post_updates.EntryDate DESC) AS rn
FROM table1 users
JOIN table3 post_updates
ON post_updates.userID = users.UserID
WHERE users.UserID = #UserID
) q
WHERE rn = 1

Resources