Creating a VIEW from multiple tables each with a different number of columns - asp.net

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.

Related

Selecting all max values of column for each distinct value of other column

I am trying to get a list of most used tags for posts on a website on a given day. I currently have this query:
SELECT posts.pdate, tags.tag, count(posts.pid) as post_count
FROM posts, tags
WHERE posts.pid = tags.pid
GROUP BY posts.pdate, tags.tag
ORDER BY posts.pdate;
This provides me with each distinct tag, along with the date they are used on as well as how many posts used them, returning me with this:
2020-09-10|CMPUT291|1
2020-09-10|computing|1
2020-09-10|database|2
2020-09-10|frequentTag1|2
2020-09-10|relational|2
2020-09-10|sql|1
2020-09-10|tieTag1|2
2020-09-11|Database|1
2020-09-11|data|1
2020-09-11|relational|1
2020-09-11|sql|1
2020-09-13|Database|1
2020-09-13|Sql language|1
2020-09-13|access|1
2020-09-13|frequentTag3|2
2020-09-13|query|3
2020-09-13|relational|3
2020-09-13|sql|1
2020-09-17|Database|1
2020-09-17|frequentTag3|3
2020-09-17|query|1
2020-09-17|relational|1
2020-09-17|sql|1
2020-09-17|sql language|1
2020-09-20|RELATIONAL|1
2020-09-20|database|1
2020-09-20|query|1
2020-09-20|sql language|1
2020-09-25|database|1
2020-09-25|sql language|1
2020-09-30|boring|2
2020-09-30|extra tag|1
2020-09-30|fun|3
2020-09-30|just here|1
2020-09-30|more tag|1
2020-09-30|sleep|3
2020-09-30|tag tag|1
2020-09-30|tag test|1
2020-09-30|test tag|1
But, I now need to make it only give me the rows that have the max (or all of them with max in case of a tie) for each date.
I WANT to be able to use MAX(count(posts.pid)) but I know that doesn't work so I need to find an alternative.
I should get a final result of this:
2020-09-10|database|2
2020-09-10|frequentTag1|2
2020-09-10|relational|2
2020-09-10|tieTag1|2
2020-09-11|Database|1
2020-09-11|data|1
2020-09-11|relational|1
2020-09-11|sql|1
2020-09-13|query|3
2020-09-13|relational|3
2020-09-17|frequentTag3|3
2020-09-20|RELATIONAL|1
2020-09-20|database|1
2020-09-20|query|1
2020-09-20|sql language|1
2020-09-25|database|1
2020-09-25|sql language|1
2020-09-30|fun|3
2020-09-30|sleep|3
Any help would be greatly appreciated.
APPLICABLE SCHEMA:
create table posts (
pid char(4),
pdate date,
title text,
body text,
poster char(4),
primary key (pid),
foreign key (poster) references users
);
create table tags (
pid char(4),
tag text,
primary key (pid,tag),
foreign key (pid) references posts
);
You can use RANK() window function:
SELECT pdate, tag, post_count
FROM (
SELECT p.pdate,
t.tag,
COUNT(*) post_count,
RANK() OVER (PARTITION BY p.pdate ORDER BY COUNT(*) DESC) rnk
FROM posts p INNER JOIN tags t
ON p.pid = t.pid
GROUP BY p.pdate, t.tag
)
WHERE rnk = 1
ORDER BY pdate, tag;
You should use a proper JOIN with an ON clause instead of that outdated syntax with the WHERE clause.

How can I get values values from a table and also not in that table in SQLite?

I have two tables: Player(name, email) and TeamPlayer(PlayerName, Team, Active). Tables Player and TeamPlayer are connected via Player.name = TeamPlayer.PlayerName.
I want to get all the elements of TeamPlayer, but also the elements in Player not in TeamPlayer. The attribute Active is important also. I execute the next command, but it did not work:
SELECT DISTINCT Player.Name, TeamPlayer.Team, TeamPlayer.Active FROM Player LEFT JOIN TeamPlayer ON TeamPlayer.PlayerName=Player.Name ORDER BY TeamPlayer.Active;
Is it possible?
You can use UNION ALL for the table TeamPlayer and the rows from Player that don't exist in TeamPlayer:
SELECT PlayerName AS Name, Team, null AS email, Active
FROM TeamPlayer
UNION ALL
SELECT t.Name, null, t.email, 0
FROM Player t
WHERE NOT EXISTS (
SELECT 1 FROM TeamPlayer
WHERE PlayerName = t.Name
)
ORDER BY Active
Since the 2 tables don't have the same columns, the non existing columns for each case will be NULL or 0 for the column Active.
You can change it as you wish.

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

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
)

SQL Select Query Asp.Net

I have a product page on a webpage that shows categories of products. This is done with a listview populated from a database. The issue that I have is that the main supplier has demanded that their products are first in the category list. So what I need to do is run a query that will return the results, display those two categories first and then display the rest alphabetically.
So I've been trying to do this using a UNION ALL query like this:
SELECT cat, cat_id, image FROM prod_categories WHERE cat_id = 19 OR cat_id = 65
UNION ALL
SELECT cat, cat_id, image FROM prod_categories WHERE cat_id <> 19 AND cat_id <> 65
I thought with a union like this it would display the results of the first select query first, but it's not doing that.
I can add an 'order by cat' clause on the end, but obviously that only displays them in the correct order if the two categories I want to display come first alphabetically, which they don't.
If anyone has any ideas how to do this it would be greatly appreciated.
Thanks
How about this:
SELECT cat, cat_id, image FROM prod_categories
order by case when cat_id in (19, 65) then 1 else 2 end, cat_id
Cuts out the need to UNION altogether. Might even produce a more efficient execution plan (possibly...).
(using Transact-SQL for SQL Server - the exact syntax may have to be tinkered for MySql etc)
Try something like this.
SELECT cat, cat_id, image, 1 as [srt]
FROM prod_categories WHERE cat_id = 19 OR cat_id = 65
UNION ALL
SELECT cat, cat_id, image, 2 as [srt]
FROM prod_categories WHERE cat_id <> 19 AND cat_id <> 65
ORDER BY srt ASC, cat_id
Don't hard-code this into your query. What happens when the next supplier wants to come second? Or last? For that matter, you may want to list categories in some sort of "group", anyways.
Instead, you should be using an ordering table (or multiple). Something simple to get you started:
CREATE TABLE Category_Order (categoryId INTEGER -- fk to category.id, unique
priority INTEGER) -- when to display category
Then you want to insert the values for the current "special" categories:
INSERT INTO Category_Order (categoryId, priority) VALUES (19, 2147483647), (65, 0)
You'll also need an entry for rows that are not currently prioritized:
INSERT INTO Category_Order (categoryId, priority)
SELECT catId, -2147483648
FROM prod_categories
WHERE catID NOT IN (19, 65)
Which can then be queried like this:
SELECT cat, cat_id, image
FROM prod_categories
JOIN Category_Order
ON category_id = cat_id
ORDER BY priority DESC, cat
If you write a small maintenance program for this table, you can then push re-ordering duties off onto the correct business department. Reordering of entries can be accomplished by splitting the difference between existing entries, although you'll want a procedure to re-distribute if things get too crowded.
Note that, in the event your db supports a clause like ORDER BY priority NULLS LAST, the entries for non-prioritized categories are unnecessary, and you can simply LEFT JOIN to the ordering table.

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.

Resources