Displaying different values from same table and column after comparing - sql

public partial class UserProfile : System.Web.UI.Page
{
private static int _userId = 0 ;
protected void Page_Load(object sender, EventArgs e)
{
string FoB;
if (Session["user"] != null)
{
_userId = DataManager.GetUserId(Session["user"].ToString());
}
string connection = WebConfigurationManager.ConnectionStrings["Database"].ConnectionString;
SqlConnection conn = new SqlConnection(connection);
SqlCommand comm = new SqlCommand("SELECT * from dbo.Rating where UserID=_userId", conn);
SqlDataReader reader;
conn.Open();
reader = comm.ExecuteReader();
reader.Read();
FoB = reader["GenreID"].ToString();
if(FoB=="1" )
{
FB.Text = reader["RatingValue"].ToString();
};
}
while (reader.HasRows);
reader.Close();
conn.Close();
}
}
I have a table named rating. It has 4 columns
RatingId, UserID, GenreID,Rating value
I want to display rating value on a label based on the current user logged in and different rating value against different Genres. UserID and GenreID are foreign keys from table Genre and User.
Edit (comment)
CREATE TABLE [dbo].[Rating] (
[RatingID] INT IDENTITY (1, 1) NOT NULL,
[UserID] INT NULL, [GenreID] INT NOT NULL,
[RatingValue] INT NOT NULL,
PRIMARY KEY CLUSTERED ([RatingID] ASC),
CONSTRAINT [FK_Rating_Genre] FOREIGN KEY ([GenreID])
REFERENCES [dbo].[Genre] ([GenreID])
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT [FK_Rating_User] FOREIGN KEY ([UserID])
REFERENCES [dbo].[User] ([UserID])
ON DELETE CASCADE ON UPDATE CASCADE );
I want to show 8 different rating values of 8 different genres by 1 single current user.

If I understand you correctly, you want to map your label to different columns, based on another, discriminating column:
using (var conn = new SqlConnection(connection))
using (var comm = new SqlCommand("SELECT * from dbo.Rating where UserID=#userId", conn))
{
comm.Parameters.AddWithValue("#userId", _userId);
conn.Open();
using (var reader = comm.ExecuteReader())
{
if (reader.HasRows && reader.Read())
{
FB.Text = reader["GenreID"].ToString() == "1"
? reader["RatingValue"].ToString();
: reader["SomeOtherColumn"].ToString();
}
}
}
If one or more of the columns to be mapped reside in another table other than Rating, you'll need to join to that table - we'll need to see your table structures to help you.
Edit, re displaying 8 Genres
I've assumed the User and Genre tables both have a column Name - join to these tables to look up the rating. The GROUP and MAX will eliminate any cases where the same user has more than one rating in the same Genre (switch the MAX to AVG or MIN if you need otherwise). Top 8 will restrict the genres. So adjust the Sql like so:
SELECT TOP 8 u.Name AS UserName, g.Name as GenreName, MAX(r.RatingValue) AS TopRating
FROM dbo.Rating r
INNER JOIN dbo.[User] u
ON r.UserId = u.UserID
INNER JOIN dbo.[Genre] g
ON r.GenreID = g.GenreID
WHERE UserID=#userId
GROUP BY u.Name, g.Name
ORDER BY g.Name;
Now, for user interface, you won't be able to display a table in a single label. The easiest would simply be to bind the result of the reader directly to a new GridView control on your WebForm
using (var reader = comm.ExecuteReader())
{
if (reader.HasRows)
{
gridView.DataSource = reader;
gridView.DataBind();
}
}
This will show a table with 3 columns matching the selected columns, and and up to 8 rows.

Related

Trying to make query on condition

I read most of the solutions here with similar questions and it did not solve my problem and I cannot find anything online that can help me.
I am trying to make query on condition where user_id = session user_id but I get error when I make INNER join
ambiguous column name
for this
public List<CartModelClass>getCarts1(){
SQLiteDatabase db = getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String[] sqlSelect = { "ID" , "user_id", "food_id", "quantity", "price", "origin", "destination","description","company_name","search_id"};
String sqltable2 = "OrderDetails LEFT JOIN OrderDetails WHERE user_id LIKE '%%' ";
qb.setTables(sqltable2);
Cursor c = qb.query(db,sqlSelect, null, null ,null ,null ,null);
final List<CartModelClass> result = new ArrayList<>();
if (c.moveToFirst()) {
do {
result.add(new CartModelClass(
c.getString(c.getColumnIndex("user_id")),
c.getString(c.getColumnIndex("food_id")),
c.getString(c.getColumnIndex("quantity")),
c.getString(c.getColumnIndex("price")),
c.getString(c.getColumnIndex("origin")),
c.getString(c.getColumnIndex("destination")),
c.getString(c.getColumnIndex("description")),
c.getString(c.getColumnIndex("company_name")),
c.getString(c.getColumnIndex("search_id"))
));
} while (c.moveToNext());
}
return result;
}
so I changed InnerJoin and made it just table where user_id like"%%" but I only get the last user_id who added to cart and show all data for all users
I want to show only added cart for user_id = session user_id so i can use it in here
loadListFood
private void loadListFood(){
sessionManager= new SessionManager(getActivity());
final Hashmap<String, String> user = sessionManager.getUserDetail();
user.get(USER_ID);
listdata = new Database(this.getContext.getCarts1());
for(CartModelClass order : listdata)
user_id = order.getUser_id
if(user.get(USER_ID).equals(user_id)){
listdata = new Database(this.getContext()).getCarts();
adapter = new CartAdapter(listdata, this.getContext());
recyclerView.setAdapter(adapter);
int total = 0;
for (CartModelClass order : listdata) {
total += (Integer.parseInt(order.getPrice())) * (Integer.parseInt(order.getQuantity()));
Locale locale = new Locale("en", "US");
NumberFormat fmt = NumberFormat.getCurrencyInstance(locale);
txtTotalPrice.setText(fmt.format(total));
}
}else {
Toast.makeText(getContext(), "No Cart Added", Toast.LENGTH_LONG).show();
}
}
You are self joining the table OrderDetails.
In this case you must set aliases to both copies of the table, like:
OrderDetails as o1 LEFT JOIN OrderDetails as o2 ...
Now in the ON clause you must qualify the column names properly, like:
ON o1.user_id = o2.something
If you don't, you get that error message, because the column name user_id could belong to either of the 2 copies of the table.
Also:
What is session user_id? Is it a column name?
If it is then the problem is that it contains a space in its name.
Enclose it in square brackets, so the statemnet should be:
OrderDetails as o1 LEFT JOIN OrderDetails as o2
ON o1.user_id = o2.[session user_id]

Fluent Nhibernate join on non foreign key property

I can't find this anywhere, but it seems pretty trivial. So, please excuse if this is a duplicate.
I have something like:
public class Doctor : Entity
{
...some other properties here...
public virtual string Email { get; set; }
}
public class Lawyer : Entity
{
...some other properties here...
public virtual string Email { get; set; }
}
I want to return all doctors where there is no email match in the Lawyers table like:
select * from Doctors d
where d.Email not in
(select l.Email from Lawyers l where l.Email is not null)
or using a join:
select d.* from Doctors d
left join Lawyers l on l.Email = d.Email
where l.Email is null
The problem is that the Email is of course not set up as a foreign key. I have no mapped property on the Doctor entity that maps to Lawyer.
What I've tried so far:
ICriteria criteria = Session.CreateCriteria(typeof(Doctor))
.CreateAlias("Lawyers.Email", "LawyerEmail", JoinType.LeftOuterJoin)
.Add(Restrictions.IsNull("LawyerEmail"));
return criteria.List<Doctor>();
But, I get a "cannot resolve property Lawyer of MyPlatform.MyNamespace.Doctor" error. Any ideas how to set up my DoctorMap and adjust the criteria tomfoolery to achieve this?
NHibernate for the loss........Entity Framework for the win....
We can achieve that with a feature called subquery:
// a inner SELECT to return all EMAILs from Lawyer table
var subQuery = DetachedCriteria.For<Lawyer>()
.SetProjection(Projections.Property("Email"));
// the root SELECT to get only these Doctors
var criteria = session.CreateCriteria<Doctor>();
// whos email is not in the sub SELECT
criteria.Add(Subqueries.PropertyNotIn("Email", subQuery));
// get first 10
var result = criteria
.SetMaxResults(10)
.SetFirstResult(0) // paging
.List<Doctor>();

How to limit Entites to particular Database in Multiple Database FluentNhibernate Application

I'm done configuring the Fluent NHibernate application using multiple databases.
When I run the application, I see that the session is creating the same tables in all the databases.
I tried limiting the creation by using the following line of code in Mapping class
Schema("Monkey") <- in monkey ClassMap
Schema("Banana") <- in Banana ClassMap
The SQL Query Generated:
if exists (select * from dbo.sysobjects where id = object_id(N'Banana.[Banan
a]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Banana.[Banana]
if exists (select * from dbo.sysobjects where id = object_id(N'Monkey.[Monke
y]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Monkey.[Monkey]
create table Banana.[Banana] (
Id INT IDENTITY NOT NULL,
Color NVARCHAR(255) null,
primary key (Id)
)
At the above point the debugger caught an error saying:
The specified schema name "Banana" either does not exist or you do not
have permission to use it.
only add the the relevant tables to the sessionfactory for each database. I would seperate them per namespaces: "BananaDbMaps" and "MonkeyDbMaps"
foreach (var dataBase in dataBases)
{
var model = new PersistenceModel();
foreach (var type in Assembly.GetExecutingAssembly().GetExportedTypes())
{
if (!type.IsInterface && !type.IsAbstract && type.IsSubclassOf(typeof(IMappingProvider)) && type.Namespace.EndsWith(dataBase.Key + "DbMaps"))
{
model.Add(type);
}
}
config = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(dataBase.Value))
.Mappings(m => m.UsePersistenceModel(model))
.BuildConfiguration();
_allFactories.Add(dataBase.Key, config.BuildSessionFactory());
}

LINQ getting Distinct values

I know there are several questions regarding this topic. However; I cannot find one that is directly related to my problem.
I have 3tables in a DB and the PK's from those 3 tables form a composite PK in a XRef table.
I need to be able to select Distinct items based on 2 of the keys just for display on a report.
public IEnumerable<AssemblyPrograms> GetProgramAssemblies()
{
var assembliesList = (from c in eModel.Assemblies.ToList()
join d in eModel.Programs_X_Assemblies_X_Builds
on c.AssemblyID equals d.AssemblyID
join p in eModel.Programs
on d.ProgramID equals p.ProgramID
join a in eModel.AssemblyTypes
on c.AssemblyTypeID equals a.AssemblyTypeID
select new AssemblyPrograms
{
AssemblyID = c.AssemblyID
,ProgramID = d.ProgramID
,AssemblyName = c.AssemblyName
,AssemblyPrefixName = c.AssemblyPrefixName
,ProgramName = p.ProgramName
,AssemblyTypeName = a.AssemblyTypeName
,AssemblyTypeID = a.AssemblyTypeID
});
return assembliesList;
}
This is my query and what I need to pull out of the tables
In my XRef table I have AssemblyID, ProgramID and BuildID as my composite PK.
There can be a many-many relationship from AssemblyID to ProgramID. The BuildID is the key that separates them.
I need to pull Distinct AssemblyID to ProgramID relationships for my report, the BuildID can be ignored.
I have tried .Distinct() in my query and a few other things to no avail.
I would appreciate any help anyone could give me.
Thanks
How about a Distinct overload that accepts a custom equality comparer? Something like this:
class AssemblyComparer : EqualityComparer<AssemblyPrograms> {
public override bool Equals(AssemblyPrograms x, AssemblyPrograms y) {
return x.ProgramID == y.ProgramID && x.AssemblyID == y.AssemblyID;
}
public override int GetHashCode(AssemblyPrograms obj) {
return obj.ProgramID.GetHashCode() ^ obj.AssemblyID.GetHashCode();
}
}

SQL to batch re-tag items

I've got a MySQL database with typical schema for tagging items:
item (1->N) item_tag (N->1) tag
Each tag has a name and a count of how many items have that tag
ie:
item
(
item_id (UNIQUE KEY)
)
item_tag
(
item_id (NON-UNIQUE INDEXED),
tag_id (NON-UNIQUE INDEXED)
)
tag
(
tag_id (UNIQUE KEY)
name
count
)
I need to write a maintenance routine to batch re-tag one or more existing tags to a single new or existing other tag. I need to make sure that after the retag, no items have duplicate tags and I need to update the counts on each tag record to reflect the number of actual items using that tag.
Looking for suggestions on how to implement this efficiently...
if i understood you correctly then you could try something like this:
/* new tag/item table clustered PK optimised for group by tag_id
or tag_id = ? queries !! */
drop table if exists tag_item;
create table tag_item
(
tag_id smallint unsigned not null,
item_id int unsigned not null,
primary key (tag_id, item_id), -- clustered PK innodb only
key (item_id)
)
engine=innodb;
-- populate new table with distinct tag/items
insert ignore into tag_item
select tag_id, item_id from item_tag order by tag_id, item_id;
-- update counters
update tag inner join
(
select
tag_id,
count(*) as counter
from
tag_item
group by
tag_id
) c on tag.tag_id = c.tag_id
set
tag.counter = c.counter;
An index/constraint on the item_tag table can prevent duplicate tags; or create the table with a composite primary key using both item_id and tag_id.
As to the counts, drop the count column from the tag table and create a VIEW to get the results:
CREATE VIEW tag_counts AS SELECT tag_id, name, COUNT(*) AS count GROUP BY tag_id, name
Then your count is always up to date.
This is what I've got so far, which seems to work but I don't have enough data yet to know how well it performs. Comments welcome.
Some notes:
Had to add a unique id field to to the item_tags table get the duplicate tag cleanup working.
Added support for tag aliases so that there's a record of retagged tags.
I didn't mention this before but each item also has a published flag and only published items should affect the count field on tags.
The code uses C#, subsonic+linq + "coding horror", but is fairly self explanatory.
The code:
public static void Retag(string new_tag, List<string> old_tags)
{
// Check new tag name is valid
if (!Utils.IsValidTag(new_tag))
{
throw new RuleException("NewTag", string.Format("Invalid tag name - {0}", new_tag));
}
// Start a transaction
using (var scope = new SimpleTransactionScope(megDB.GetInstance().Provider))
{
// Get the new tag
var newTag = tag.SingleOrDefault(x => x.name == new_tag);
// If the new tag is an alias, remap to the alias instead
if (newTag != null && newTag.alias != null)
{
newTag = tag.SingleOrDefault(x => x.tag_id == newTag.alias.Value);
}
// Get the old tags
var oldTags = new List<tag>();
foreach (var old_tag in old_tags)
{
// Ignore same tag
if (string.Compare(old_tag, new_tag, true)==0)
continue;
var oldTag = tag.SingleOrDefault(x => x.name == old_tag);
if (oldTag != null)
oldTags.Add(oldTag);
}
// Redundant?
if (oldTags.Count == 0)
return;
// Simple rename?
if (oldTags.Count == 1 && newTag == null)
{
oldTags[0].name = new_tag;
oldTags[0].Save();
scope.Complete();
return;
}
// Create new tag?
if (newTag == null)
{
newTag = new tag();
newTag.name = new_tag;
newTag.Save();
}
// Build a comma separated list of old tag id's for use in sql 'IN' clause
var sql_old_tags = string.Join(",", (from t in oldTags select t.tag_id.ToString()).ToArray());
// Step 1 - Retag, allowing duplicates for now
var sql = #"
UPDATE item_tags
SET tag_id=#newtagid
WHERE tag_id IN (" + sql_old_tags + #");
";
// Step 2 - Delete the duplicates
sql += #"
DELETE t1
FROM item_tags t1, item_tags t2
WHERE t1.tag_id=t2.tag_id
AND t1.item_id=t2.item_id
AND t1.item_tag_id > t2.item_tag_id;
";
// Step 3 - Update the use count of the destination tag
sql += #"
UPDATE tags
SET tags.count=
(
SELECT COUNT(items.item_id)
FROM items
INNER JOIN item_tags ON item_tags.item_id = items.item_id
WHERE items.published=1 AND item_tags.tag_id=#newtagid
)
WHERE
tag_id=#newtagid;
";
// Step 4 - Zero the use counts of the old tags and alias the old tag to the new tag
sql += #"
UPDATE tags
SET tags.count=0,
alias=#newtagid
WHERE tag_id IN (" + sql_old_tags + #");
";
// Do it!
megDB.CodingHorror(sql, newTag.tag_id, newTag.tag_id, newTag.tag_id, newTag.tag_id).Execute();
scope.Complete();
}