WCF returning wrong view output - wcf

Here I struck in some strange situation.
I created a view in SQL Server
Create View [Adm].[VwSurveyReport]
as
SELECT q.QuestionID,q.Question,p.dtStart,p.dtEnd,u.OrgCode,u.UserID,u.RoleID,
(case tc.blanswer
when 1 then 1
when 0 then 0
end) as AnsYes,
(case tc.blanswer
when 1 then 0
when 0 then 1
end) as AnsNo
from dbo.SurveyQuestions as q
left outer join dbo.surveyTransChild as tc on tc.questionID=q.questionID
left outer join dbo.surveyTransParent as tp on tp.SurveyTransID=tc.SurveyTransID
left outer join dbo.SurveyParent as p on p.surveyID=tp.surveyID
left outer join adm.masFEUser as u on tp.Userid=u.Userid
where p.dtStart IS Not NULL
GO
and my code behind is
List<ThePayWcfRef.VwSurveyReport> data = new List<ThePayWcfRef.VwSurveyReport>();
data = (from v in entities.VwSurveyReports
where 1 == 1
select v).ToList();
When I run select query in SQL Server it is showing exact output which I want
UserID RoleID AnsYes AnsNo
m6018upl 2 1 0
m6018upl 2 1 0
m6018app1 4 1 0
m6018app1 4 0 1
but in my code behind I am getting wrong data into "data" list
UserID RoleID AnsYes AnsNo
m6018app1 4 1 0
m6018app1 4 0 1
m6018app1 4 1 0
m6018app1 4 0 1
AnsYes, AnsNo and UserID are wrong
Please help me.
Thanks in advance.

I don't know what your EF model looks like - but the issue with views in Entity Framework often boils down to this:
since a view by default doesn't have a primary key, EF will "infer" an "entity key" based on all the columns in the view that are guaranteed to be NOT NULL
those columns might (or might not) make a good surrogate primary key
when EF loads the data, it will look at those columns in the primary key; if an entity with that same EntityKey has already been loaded from the database, EF will not load the data again, but reference that entity it already has in memory
All this together can lead to unexpected results on EF using views.
There are a number of solutions around this:
make sure to include all primary keys from all included base tables in your view; that way, the table's primary keys will certainly be part of the view's surrogate primary key for EF and thus they will guarantee uniqueness
create your own, individual pseudo primary key by having a e.g. ROW_NUMBER() column in your view, just to make sure each row has something that's unique for that row, in order to prevent EF from "short-circuiting" entities because it thinks it's already loaded that entity...

Related

SQL select from two tabels wrong result

I can not understand what I am doing wrong.
My array:
ps_product
id_product
active
1
1
2
1
and
ps_product_sync
id_product
status
1
0
2
1
and my SQL code
SELECT pr_product.id_product, pr_product.active
FROM pr_product, pr_product_sync
WHERE pr_product.active = pr_product_sync.status
I get a result like this:
id_product
status
2
1
2
1
2
1
...
..
24 rows
I try the same with inner but result is the same, I don't have duplicates in the arrays... I don't understand why I get one row 24 times
PS. all tables looks good before posting/saving
If you query two tables and include both in the FROM clause, you create a Cartesian product of these tables. In other words, if one table has 4 rows and the other 6 rows, the result is 24 rows.
It is better to create an INNER JOIN using the key of the first table and the foreign key of the second table.
Change your query accordingly
SELECT pr_product.id_product, pr_product.active
FROM pr_product
INNER JOIN pr_product_sync
ON pr_product.id_product = ps_product_sync.id_product
WHERE pr_product.active = pr_product_sync.status
Of course, you could also compare the Keys in the WHERE clause or eliminate duplicates using DISTINCT. IMHO the most understandable solution is an INNER JOIN.
I hope this solves your problem.
Missing the primary key join.
Add:
WHERE
pr_product.id_product=pr_product_sync.id_product
AND pr_product.active=pr_product_sync.status

Merge two versions of database tables with conflicting keys

I have been asked to merge 2 Access databases. They are conflicting versions of the same file.
A database was emailed to somebody. (I know.) Somebody added records to the 'main' copy while somebody else added records to their copy. I want to add the new records from the 'unauthorised' copy into the main version, before utterly destroying all other copies.
Unfortunately, the database has several related tables. As would naturally happen when records are added, records in different versions have conflicting primary keys. These conflicting keys are also used as foreign keys in the new records. A foreign key reference to ID x means different things in the 2 versions.
Is there any hope? I thought of maybe importing it all into excel and using formulas to update the primary and foreign keys.
Is there any way to fix this programatically?
EDIT: Here is a picture showing the full relationships. Tables teachers, tests, and test_results have been changed; the others are the same in both.
In the main database, add a Long field named [oldID] to each table into which you need to append data. Then create Linked Tables pointing to the relevant tables in the "other" database. Since the table names are the same, the linked tables will have a '1' appended to them.
For this example, we have
[teachers]
ID teacher oldID
-- -------- -----
1 TeacherA
2 TeacherB
3 TeacherX
[teachers1]
ID teacher
-- --------
1 TeacherA
2 TeacherB
3 TeacherY
[tests]
ID test_name teacher oldID
-- -------------- ------- -----
1 TeacherA_Test1 1
2 TeacherA_Test2 1
3 TeacherB_Test1 2
4 TeacherX_Test1 3
[tests1]
ID test_name teacher
-- -------------- -------
1 TeacherA_Test1 1
2 TeacherA_Test2 1
3 TeacherB_Test1 2
4 TeacherY_Test1 3
5 TeacherY_Test2 3
Make a note of where the tables diverge. In this case the [teachers] tables diverge after ID=2. So, insert the new rows from [teachers1] into [teachers], putting [teachers1].[ID] into [teachers].[oldID] so we can map old IDs to new ones:
INSERT INTO [teachers] ([teacher], [oldID])
SELECT [teacher], [ID] FROM [teachers1] WHERE [ID]>2
So now we have
[teachers]
ID teacher oldID
-- -------- -----
1 TeacherA
2 TeacherB
3 TeacherX
4 TeacherY 3
Now when we append the new rows from [tests1] into [tests] we can use an INNER JOIN on [teachers].[oldID] to adjust the foreign key values that get inserted:
INSERT INTO [tests] ([test_name], [teacher], [oldID])
SELECT [tests1].[test_name], [teachers].[ID], [tests1].[ID]
FROM [tests1] INNER JOIN [teachers] ON [tests1].[teacher]=[teachers].[oldID]
giving us
[tests]
ID test_name teacher oldID
-- -------------- ------- -----
1 TeacherA_Test1 1
2 TeacherA_Test2 1
3 TeacherB_Test1 2
4 TeacherX_Test1 3
5 TeacherY_Test1 4 4
6 TeacherY_Test2 4 5
Notice how the [teacher] foreign key has been mapped from the value 3 in [tests1] to 4 in [tests], reflecting the new [teachers].[ID] value for 'TeacherY'.
You can then repeat the process for child tables of [tests].
(Once the cleanup is complete you can remove the table links and drop the [oldID] columns.)
Is there any way to fix this programatically?
No. This must be done by a human capable of reading and understanding the data and taking decisions.
Create a query with an inner join between table one and table two, another query with an outer join between table one and table two, and another query with an outer join between table two and table one.
Now you can study the differences and decide which version of similar records to be kept and which records are completely new and should be kept - some with a new Primary Key.

Merge and order rows

I have a table in the following structure. I am writing a query to get all item_ids where key_name='topic' and key_string_value='investing', which is the simple part.
select item_id from table where key_name='topic' and key_string_value='investing'
But then for all the item_ids returned above, I want to order them by the values set for each item_id in key_name='importance' and key_name='product'.The table structure is making it very difficult as I am not an SQL expert. Any help would be appreciated.
item_id key_name key_string_value Key_float_value
1 topic investing null
1 importance null 500
1 product A null
1 product B null
2 topic Starting null
2 product B null
2 importance null 300
2 topic retail null
3 importance null 400
3 topic investing null
3 product C null
4 topic Starting null
4 topic investing null
4 importance null 400
4 product D null
#Schwern is on right - your structure should be normalized, and the names should be better too. All this makes me think: homework.
The answer to the homework question is a self join, and looks like this:
select t1.item_id , imp.key_float_value, prd.key_string_value
from [table] t1
LEFT OUTER JOIN [table] imp on imp.item_id = t1.item_id and imp.key_name='importance'
LEFT OUTER JOIN [table] prd on prd.item_id = t1.item_id and prd.key_name='product'
where t1.key_name='topic' and t1.key_string_value='investing'
ORDER BY imp.key_float_value, prd.key_string_value
The square brackets on `[table] are because the use of the table keyword as the table name requires the name to be delimited. Square brackets for TSQL. Others use double quotes (")
You have a very poorly design table that will be slow and difficult to work with. SQL is not a key/value store; it works on rows, columns and relationships. Rather than fight it, I would suggest redesigning it. Either use a NoSQL database which is easier to use and works more like normal programming data structures, or redesign it.
Here's the redesign I would suggest.
CREATE TABLE item (
id INTEGER PRIMARY KEY,
importance INTEGER DEFAULT 0
);
CREATE TABLE item_topics (
item_id INTEGER REFERENCES item(id),
topic TEXT NOT NULL
);
CREATE TABLE item_products (
item_id INTEGER REFERENCES item(id),
product TEXT NOT NULL
);
The item itself, and any scalar (ie. single value) attributes go into one table. Anything which can be a list (products and topics) needs its own table relating each item to its elements. If this seems clunky, that's because it is, but that's how SQL works.
To find all items whose topic is investing, you have to join on the item_topics table.
SELECT item.id
FROM item
JOIN item_topics ON item.id = item_topics.id
WHERE topic = 'investing'
Then to order them, add ORDER BY item.importance.

SQL - Linking two tables

I have two tables, specifically, they contain standard and specific parameters respectively.
Table1:
PKParameter Name Unit
1 Temperature K
2 Length mm
3 Pressure bar
Table2:
PKSpecParam Name Unit
1 Weight kg
2 Area m2
PKParameter ans PKSpecParameter are primary keys
I would like to combine these two tables into a third table which will keep track of the primary keys so I can reference any of the parameters, regardless of the table they are from.
For example:
PKCombined PKParameter PKSpecParameter
1 1 NULL
2 2 NULL
3 3 NULL
4 NULL 1
5 NULL 2
Now I would like to use PKCombined primary key to reference parameter
Maybe there is a better way to do this, but I've just started meddling with databases.
Select a.PKParameter , a.name,a.unit,b.PKSpecParam , b.name,b.unit
from table1 a outer join table2 b on a.pkparameter=b.pkspecparam
However, this will give out null values if number of entries in pkparameter and pkspecparam dont match

SQL Constraint/Check on Join tables

I have three tables: store, product, storeproduct.
It doesn't really matter what's in the store and the product table, just know there is a storeID in the store table, and a productID in the product table. However the storeproduct table keeps track of the different products each store has. So the storeproduct table has two columns. The storeID column, and the productID column, both foreign keys from the store and the product table.
Is there a way to put a constraint or check on any of the table to make sure that a store must have more than 0 products, and less than 50 products.
Note: I do not want a select statement to do this. I just want to know if there is a way to put a constraint or a check when creating the tables.
The point of this is so a user cannot insert into the storeproduct table if there are already 50 products(rows) with the same storeID, or delete from the storeproduct table if deleting a row will cause the last row with that storeID to be gone.
The storeproduct table might look like this
storeID productID
1 1
1 2
1 3
2 4
2 5
2 6
2 7
3 4
3 2
3 6
3 1
3 8
Actually, depending on your database you may be able to do this.
Oracle (and maybe others) provide materialized views which you can apply constraints to. So you could create the MV with a column PRODUCTS_IN_STORES (being something like select storeID, count(*) as PRODUCTS_IN_STORES from stores left outer join storeproduct on store.storeid=storeproduct.storeid group by store.storeid .Then put a constraint on it asserting that PRODUCTS_IN_STORES is between 0 and 50 or whatever.
http://www.sqlsnippets.com/en/topic-12896.html
and
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:21389386132607
Not a complete answer for you, but something to think about and hopefully set you on your way.