Mysql: Conditions on a unique primary key tuple - mysql

Short
Is it possible, that if I have a unique primary key tuple (idUser,idRep) that for each idUser n only certain combinations with idRep are possible?
For example that the following groups of keys are allowed:
(n,1);(n,2);(n,3) OR (n,1);(n,6) OR (n,2);(n,5) OR (n,4);(n,3) OR (n,7)
but not the keys (n,1) and (n,7) together?
Long question
I have the following table
idUser | idGroup | idType |
where the primary key is (idUser,idGroup). There are three different values for idGroup: 1,2,3. For almost all users the idType is always the same independent of the group, but there are a few exceptions. Thus the table looks like that
idUser | idGroup | idType
--------------------------
1 | 1 | 43
1 | 2 | 43
1 | 3 | 43
2 | 1 | 22
2 | 2 | 22
3 | 1 | 12
3 | 3 | 12
4 | 2 | 5
4 | 3 | 6
I thought I could avoid the redundancy with a column idRep which contains the information in which groups one user is as follows
1 -> user is in group 1
2 -> user is in group 2
3 -> user is in group 1 and 2 (1+2=3)
4 -> user is in group 3
5 -> user is in group 1 and 3 (4+1=5)
6 -> user is in group 2 and 3 (4+2=6)
7 -> user is in group 1 and 2 and 3 (4+2+1=7)
this would reduce redundancy and the above table would shrink to
idUser | idRep | idType
-------------------------
1 | 7 | 43
2 | 3 | 22
3 | 5 | 12
4 | 2 | 5
4 | 4 | 6
However the disadvantage is that its possible that even if (idUser,idRep) is a primary key there is the possibility of a wrong entry like
idUser | idRep | idType
-------------------------
1 | 7 | 43
1 | 1 | 42
In this case, there is a contradiction about idType for idUser 1 in group 1.
So my question is: Is it possible to say that for a specific idUser n only the following groups of keys are allowed:
(n,1);(n,2);(n,3) OR (n,1);(n,6) OR (n,2);(n,5) OR (n,4);(n,3) OR (n,7)
but not for (n,1) and (n,7)?

Related

inserting data from 2 tables into new table i.e. table_out as below

---I have 2 tables--
table1:
venu_id | venu_code| venu_capacity | venu_address|
--------------------------------------------------
1 | 29 | 5 | delhi |
2 | 29 | 5 | delhi |
3 | 28 | 3 | banglore |
table2:
application_id| can_name | date |fee_payment_status|can_name
------------------------------------------------------------------
5516 |abhishek |28‑OCT‑1990 | success |abhishek
5517 |robin |28‑OCT‑1990 | success |robin
5518 |rohit |28‑OCT‑1990 | success |rohit
I want to create a new table "table_out" which has columns
Application_id, can_name, venu_id, roll_number;
example
table_out:
id |Application_id| can_name | venu_id| roll_number
--------------------------------------------------
1 | 5516 | abhishek| 29 | 290000001
2 | 5517 | robin | 29 | 290000002
3 | 5518 | rohit | 28 | 280000001
table_out connects with other tables using foreign keys and finally I want to read the data from the other 2 tables and insert it into table_out.
I want to generate roll_number which have 8 digits and starts with "venu_code" and roll_number partition by "venu_capacity" and order by "venu_address".
Example:
venu_id
venu_capacity
venu_address
55
5
Delhi
roll_number=55000001 and so on....
capacity reduce to 4 in delhi
Finally wants to insert all data from other tables into table_out with roll_number which is unique and sequential as above shown in example table_out
how to do it in mySql?

Count the rows of a table, while checking if the value is NULL or not and grouping the results by the values of another column

I am stuck trying to find a solution to my silly little problem.
The MySQL table looks as follows:
-- Create a table that will record all AdCamp hits
CREATE TABLE `advertising_campaign_hits` (
`adcamp_hit_id` INT NOT NULL AUTO_INCREMENT,
`adcamp_id` INT,
`customer_id` INT,
`recorded_at` DATETIME,
PRIMARY KEY (`adcamp_hit_id`)
) ENGINE=MyISAM;
Example values would look like this:
a_h_id | a_id | c_id | ...
1 | 1 | 1 | ...
2 | 1 | 2 | ...
3 | 1 | 3 | ...
4 | 1 | 0 | ...
5 | 1 | 0 | ...
6 | 2 | 1 | ...
7 | 2 | 0 | ...
The goal here is to count the number of hits for each of the advertising campaigns, but divide them into two groups of KnownCustomers and UnknownCustomers and then further divide them each by adcamp_id.
So the results I would expect to get are:
adcamp_id | HitsByKnown | HitsByUnknown
1 | 3 | 2
2 | 1 | 1
I am currently stuck in where I can get SQL to give me two separate rows for each of the adcamps, but the results of COUNT(*) list all of my entries.
So what I get is:
adcamp_id | HitsByKnown | HitsByUnknown
1 | 4 | 3
2 | 4 | 3
I can't figure out how to split it all up.
select adcamp_id,sum(if(customer_id>0,1,0)) as HitsByKnown,sum(if(customer_id=0,1,0)) as HitsByUnknown from advertising_campaign_hits group by adcamp_id
or even easier:
select adcamp_id,sum(customer_id!=0) as HitsByKnown,sum(customer_id=0) as HitsByUnknown from advertising_campaign_hits group by adcamp_id

Special unique columns

I have a situation where a website (a source) has multiple feeds (category separated)
Feed Table
feed_id | source_id | feed_url
1 | 1 | http://example.com/rss?category=1
2 | 1 | http://example.com/rss?category=5
3 | 2 | http://textample.com/rss
Item Table
item_id | true_id | feed_id
1 | 1332 | 1
2 | 76549 | 1
3 | 76549 | 2
4 | 76549 | 3
the true id is the id I try to get from the source site.
I want the item id 2 & 3 are the same, because they share the same source (example.com), item 4 is not the same because it has a different source (textample.com)
Is there a way I can enforce that consistency, without adding the source id to the Item Table?
RUN
ALTER TABLE `itemTable` ADD UNIQUE (`feed_id`);

Complicated MySQL Data Structure/Manipulation Problem

First off, I apologize for the length. This is kind of complicated (at least for me).
Background on the database:
I have a products, variables, and prices table. "Products" are the main information regarding a product (description, title, etc). "Prices" have information about each price (price, cost, minimum qty required, shipping cost, etc), as some products can have more than one price (a 10" widget is a different price than a 12" widget, for instance). "Variables" are variations to the product that do not change the price, such as color, size, etc.
Initially (when I built this database about 7 years ago) I had the variable information stored in the first price in a list of prices for the same product in a pipe-delimited format (yes, I know, badbadbad). This worked in general, but we've always had a problem, though, where sometimes a variable wouldn't be consistent among all the prices.
For instance, a Widget (product) may be 10" or 12" and sell for $10 and $20 (prices) respectively. However, while the 10" widget may be available in blue and red (variables), the 12" widget is only available in red. We ameliorated this problem by adding a little parenthetical statement in the incongruent variable like "Red (10" ONLY)". This sort of works, but customers are not always that smart and a lot of time is devoted to fixing mistakes when a customer selects a 12" widget in red.
I have since been tasked with modernizing the database and have decided to put the variables in their own table and making them more dynamic and easier to match with certain prices, as well as keep a more dummy-proof inventory (you can't imagine the nightmares).
My first step was to write a stored procedure on my test db (for when I do the conversion) to process all the existing variables into a new variable table (and label table, but that's not really important, I don't think). I effectively parsed out the variables and listed them with the correct product id and the product id they were initially associated with in the variable table. However, I realized this is only a part of the problem, since I (at least for the initial transformation of the database) want each variable to be listed as being connected to each price for a given product.
To do this, I created another table, like so:
tblvariablesprices
variablepriceid | variableid | priceid | productid
which is a many-to-many with the variable table.
Problems:
My problem now is, I don't know how to create the rows. I can create a left join on my prices and variables tables to get (I think) all the necessary data, I just don't know how to go through it. My sql is (mysql 5.0):
SELECT p.priceid, p.productid, variableid, labelid
FROM tblprices p
LEFT JOIN tblvariables v ON p.priceid = v.priceid
ORDER BY productid, priceid
This will get me every priceid and productid and any matching variable and label ids. This is good in certain instances, such as when I have something like:
priceid | productid | variableid | labelid
2 | 7 | 10 | 4
2 | 7 | 11 | 4
2 | 7 | 12 | 4
3 | 7 | (null) | (null) --- another price for product
because now I know that I need to create a record for priceid 2 and variableids 10, 11, 12, and then also for priceid 3 for that product. However, I also get results from this dataset for products with no variables, products with one price and multiple variables, and products with multiple prices and no variables, for instance:
priceid | productid | variableid | labelid
2 | 7 | 10 | 4
2 | 7 | 11 | 4
2 | 7 | 12 | 4
3 | 7 | (null) | (null)
4 | 8 | (null) | (null) --- 1 price no variables
5 | 9 | 13 | 5 --- mult vars, 1 price
5 | 9 | 14 | 5
5 | 9 | 15 | 6
5 | 9 | 16 | 6
6 | 10 | (null) | (null) --- mult price, no vars
7 | 10 | (null) | (null)
8 | 10 | (null) | (null)
Taking the above dataset, I want to add entries into my tblpricesvariables table like so:
variablepriceid | variableid | priceid | productid
1 | 10 | 2 | 7
2 | 11 | 2 | 7
3 | 12 | 2 | 7
4 | 10 | 3 | 7
5 | 11 | 3 | 7
6 | 12 | 3 | 7
7 | 13 | 5 | 9
8 | 14 | 5 | 9
9 | 15 | 5 | 9
10 | 16 | 5 | 9
I have thousands of records to process, so obviously doing this manually is not the answer. Can anyone at least point me in the correct direction, if not come up with a sproc that could handle this type of operation? I also would welcome any comments on how to better organize and/or structure this data.
Thank you so much for reading all this and helping me out.
How about:
SELECT DISTINCT b.variableid, a.priceid, a.productid
FROM tblprices AS a
JOIN tblprices AS b ON a.productid = b.productid
WHERE b.labelid IS NOT NULL
ORDER BY priceid;
+------------+---------+-----------+
| variableid | priceid | productid |
+------------+---------+-----------+
| 10 | 2 | 7 |
| 11 | 2 | 7 |
| 12 | 2 | 7 |
| 10 | 3 | 7 |
| 11 | 3 | 7 |
| 12 | 3 | 7 |
| 13 | 5 | 9 |
| 14 | 5 | 9 |
| 15 | 5 | 9 |
| 16 | 5 | 9 |
+------------+---------+-----------+
INSERTing into tblvariables is left as an exercise for the reader ;)
I think this should work:
SELECT v.variableid, p.productid, p.priceid
FROM tblvariables v, tblprices p
WHERE v.priceid IN (SELECT s.priceid
FROM tblprices s
WHERE s.productid = p.productid);
Next time, can you throw in create and insert statements to replicate your setup? Thanks.

Update a sorting index column to move items

If I have the following table & data to allow us to use the sort_index for sorting:
CREATE TABLE `foo` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`bar_id` INT(11) DEFAULT NULL,
`sort_index` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `foo` (`bar_id`, `sort_index`) VALUES
(1,1),(1,2),(1,3),(1,4),
(2,1),(2,2),(2,3),(2,4),(2,5);
I want to be able to do the following in the most efficient manner:
Move a foo entry to a given position (scoped by the bar_id)
Ensure that the sort_index is always 1 indexed and has no gaps
You should be able to move items to the beginning and end of the list and rule #2 should still be applied
It should be done entirely in queries and as few as possible (as the sets could be very large and looping over them doing individual UPDATEs is not ideal)
To clarify what I'm trying to do, lets assume the table was empty so we have the following data:
id | bar_id | sort_index
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 1 | 4
5 | 2 | 1
6 | 2 | 2
7 | 2 | 3
8 | 2 | 4
9 | 2 | 5
Then if we were to do the following moves
Foo 1 to sort_index 3
Foo 7 to sort_index 1
Foo 5 to sort_index 5
We should get the following data:
id | bar_id | sort_index
1 | 1 | 3
2 | 1 | 1
3 | 1 | 2
4 | 1 | 4
5 | 2 | 5
6 | 2 | 2
7 | 2 | 1
8 | 2 | 3
9 | 2 | 4
And SELECT * FROM foo ORDER BY bar_id, sort_index; gives us:
id | bar_id | sort_index
2 | 1 | 1
3 | 1 | 2
1 | 1 | 3
4 | 1 | 4
7 | 2 | 1
6 | 2 | 2
8 | 2 | 3
9 | 2 | 4
5 | 2 | 5
You should be able to do this in a single query: something along the lines of UPDATE foo SET sort_index = sort_index + 1 WHERE bar_id == b AND sort_index < s1 AND sort_index >= s2, where b is the bar_id of the row to be moved, s1 is the current sort_index of that row, and s2 is the the sort_index you want to move it to. Then, you'd just change the sort_index of the row.
You'd probably want to do the two queries inside a transaction. Also, it might speed things up if you created an index on the sort_index using something like CREATE INDEX foo_index ON foo (sort_index).
(By the way, here I'm assuming that you don't want duplicate sort_index values within a given bar_id, and that the relative order of rows should never be changed except explicitly. If you don't need this, the solution is even simpler.)