Recommendation based on Item History - recommendation-engine

I have a csv file/ table data in following format,
UserId Item1 Item2
1 url1 url3
1 url4 url6
2 url2 url3
2 url2 url4
2 url4 url6
3 url4 url6
3 url2 url3
So, here I want to predict item2 for a perticular user if value of item1 is known. Can we use collaborative filtering for the same?? If yes, please guide :)

I'm sure it would work, you've just got to figure out how you decide if a user is similar or not. The following gives you a suggestion field based on what item2 values have been paired with item1s (and vice versa) - it excludes items the user already has.. You can do much more complicated of course but here's something to get started
select *, ISNULL((SELECT STUFF
((SELECT ', ' + CAST(ITEM2 AS VARCHAR(10)) [text()] from
((select top 5 ISNULL(item2,'') item2, count(item2) as cnt from items as CountTable1 where item1=Res.item1 and item2 is not null and len(item2) > 0
and item2 not in (select item2 from items where id=Res.id UNION select item1 from items where id=Res.id)
group by item2 order by cnt desc)
UNION
/* Below includes suggestions from item1 */
(select top 5 ISNULL(item1,'') item1, count(item1) as cnt from items as CountTable2 where item2=Res.item1 and item1 is not null and len(item1) > 0
and item1 not in (select item1 from items where id=Res.id UNION select item2 from items where id=Res.id)
group by item1 order by cnt desc))
as Suggs where item1=Res.item1 FOR XML PATH('')
, TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ')
List_Output)
,'') as Suggestions from items as Res
Sql Fiddle

Related

Mariadb SQL Select count with group by and select values not null from another

I've a problem to realize my query maybe someone of you can help me :)
I have 3 tables :
1) Documents
DocRef CustRef
Doc1 Cust1
Doc2 Cust2
Doc3 Cust1
2) LinkInter
DocRef InterRef
Doc1 Inter1
Doc2 Inter2
Doc3 Inter3
3) Inter
id InterRef deliverychannel email mobilenb date status
1 Inter1 Email email1#email.be 2013-01-14T00:00:00Z ok
2 Inter1 SMS 0444111111 2013-01-12T00:00:00Z ko
3 Inter1 Other email5#email.be 2013-02-21T00:00:00Z ko
4 Inter2 Email email2#email.be 044456465465 2013-01-21T00:00:00Z ko
5 Inter3 Email 2013-01-21T00:00:00Z ko
6 Inter3 SMS 2013-01-22T00:00:00Z ko
7 Inter3 Other email3#mail.be 2013-01-22T00:00:00Z ko
to have a best view go here: sqlfiddle
The result that I want is the following:
CustRef | number of InterRef SMS KO| Last email known| Last mobilenb known
Cust1 | 2 | email5#email.be | 0444111111
I want to have all the Customers where the deliverychannel = 'SMS' and the status = 'ko', the number of Inter (Interactions) with the status 'KO', the last email known and the last mobile number known.
I've tried with 2 functions getLastEmailKnown & getLastmobilenbKnown but with my tables that count more than 10.000.000 of records it takes a lot of times
I can have this result with php page but it's not the solution, I want to have only one query
If I execute 3 queries sepately, it works but i want only one
SELECT d.CustRef, count(DISTINCT i.InterRef) , i.email, i.mobilenb
FROM Documents d
INNER join LinkInter link on link.DocRef = d.DocRef
INNER join Inter i on i.InterRef = link.InterRef
and i.deliverychannel = 'SMS'
and i.status = 'ko'
group by d.CustRef
Order by d.CustRef DESC;
SELECT distinct i.email as lastEmailKnown, d.CustRef
FROM Inter i
INNER join LinkInter link on link.InterRef = i.InterRef
INNER join Documents d on d.DocRef = link.DocRef
where d.CustRef = 'Cust1' AND email is not NULL and email <> '' ORDER by date DESC LIMIT 1;
SELECT distinct i.mobilenb as lastmobileKnown, d.CustRef
FROM Inter i
INNER join LinkInter link on link.InterRef = i.InterRef
INNER join Documents d on d.DocRef = link.DocRef
where d.CustRef = 'Cust1' AND mobilenb is not NULL and mobilenb <> '' ORDER by date DESC LIMIT 1;

can you helpe me to display the latest data on each group

I have this datatables:
table1
id category
-------------
1 a
2 b
3 c
table2
id heading category_id
----------------------
1 name 1
2 adddress 2
3 phone 3
4 email 1
I want to group this table and display the latest data for that the following query was I used:
SELECT news.id,news.image,news.heading,news.description,
news.date,news.category_id,categories.category
FROM `news`
INNER JOIN categories On news.category_id=categories.id
group by category_id
But I didnt get the latest data that I entered.
Try the query below:
SELECT *
FROM table2 AS tb2 LEFT JOIN table1 AS tb1 ON tb2.category_id = tb1.id
ORDER BY tb1.id
GROUP BY tb2.category_id

How to sum items from subtable in SQL

Let's say I have table orders
id name
1 order1
2 order2
3 order3
and subtable items
id parent amount price
1 1 1 10
2 1 3 20
3 2 2 5
4 2 5 1
I would like to create query with order with added column value. it should calculate order with all relevant items
id name value
1 order1 70
2 order2 15
3 order3 0
Is this possible with TSQL
GROUP BY and SUM would do it, need to use left join and isnull as you don't have items for all orders.
SELECT o.id, o.name, isnull(sum(i.amount*i.price),0) as value
FROM orders o
left join items i
on o.id = i.parent
group by o.id, o.name
I think you're looking for something like this
SELECT o.name, i.Value FROM orders o WITH (NOLOCK)
LEFT JOIN (SELECT parent, SUM(price) AS Value FROM items WITH (NOLOCK) GROUP BY parent) i
ON o.id = i.parent
...seems like RADAR beat me to the answer.
EDIT: missing the ON line.

Make a column values header for rest of columns using TSQL

I have following table
ID | Group | Type | Product
1 Dairy Milk Fresh Milk
2 Dairy Butter Butter Cream
3 Beverage Coke Coca cola
4 Beverage Diet Dew
5 Beverage Juice Fresh Juice
I need following output/query result:
ID | Group | Type | Product
1 Dairy
1 Milk Fresh Milk
2 Butter Butter Cream
2 Beverage
1 Coke Coca cola
2 Diet Dew
3 Juice Fresh Juice
For above sample a hard coded script can do the job but I look for a dynamic script for any number of groups. I do not have any idea how it can be done so, I do not have a sample query yet. I need ideas, examples that at least give me an idea. PIVOT looks a close option but does not looks to be fully fit for this case.
Here's a possible way. It basically unions the "Group-Headers" and the "Group-Items". The difficulty was to order them correctly.
WITH CTE AS
(
SELECT ID,[Group],Type,Product,
ROW_NUMBER() OVER (PARTITION BY [Group] Order By ID)AS RN
FROM Drink
)
SELECT ID,[Group],Type,Product
FROM(
SELECT RN AS ID,[Group],[Id]AS OriginalId,'' As Type,'' As Product, 0 AS RN, 'Group' As RowType
FROM CTE WHERE RN = 1
UNION ALL
SELECT RN AS ID,'' AS [Group],[Id]AS OriginalId,Type,Product, RN, 'Item' As RowType
FROM CTE
)X
ORDER BY OriginalId ASC
, CASE WHEN RowType='Group' THEN 0 ELSE 1 END ASC
, RN ASC
Here's a demo-fiddle: http://sqlfiddle.com/#!6/ed6ca/2/0
A slightly simplified approach:
With Groups As
(
Select Distinct Min(Id) As Id, [Group], '' As [Type], '' As Product
From dbo.Source
Group By [Group]
)
Select Coalesce(Cast(Z.Id As varchar(10)),'') As Id
, Coalesce(Z.[Group],'') As [Group]
, Z.[Type], Z.Product
From (
Select Id As Sort, Id, [Group], [Type], Product
From Groups
Union All
Select G.Id, Null, Null, S.[Type], S.Product
From dbo.Source As S
Join Groups As G
On G.[Group] = S.[Group]
) As Z
Order By Sort
It should be noted that the use of Coalesce is purely for aesthetic reasons. You could simply return null in these cases.
SQL Fiddle
And an approach with ROW_NUMBER:
IF OBJECT_ID('dbo.grouprows') IS NOT NULL DROP TABLE dbo.grouprows;
CREATE TABLE dbo.grouprows(
ID INT,
Grp NVARCHAR(MAX),
Type NVARCHAR(MAX),
Product NVARCHAR(MAX)
);
INSERT INTO dbo.grouprows VALUES
(1,'Dairy','Milk','Fresh Milk'),
(2,'Dairy','Butter','Butter Cream'),
(3,'Beverage','Coke','Coca cola'),
(4,'Beverage','Diet','Dew'),
(5,'Beverage','Juice','Fresh Juice');
SELECT
CASE WHEN gg = 0 THEN dr1 END GrpId,
CASE WHEN gg = 1 THEN rn1 END TypeId,
ISNULL(Grp,'')Grp,
CASE WHEN gg = 1 THEN Type ELSE '' END Type,
CASE WHEN gg = 1 THEN Product ELSE '' END Product
FROM(
SELECT *,
DENSE_RANK()OVER(ORDER BY Grp DESC) dr1
FROM(
SELECT *,
ROW_NUMBER()OVER(PARTITION BY Grp ORDER BY type,gg) rn1,
ROW_NUMBER()OVER(ORDER BY type,gg) rn0
FROM(
SELECT Grp,Type,Product, GROUPING(Grp) gg, GROUPING(type) tg FROM dbo.grouprows
GROUP BY Product, Type, Grp
WITH ROLLUP
)X1
WHERE tg = 0
)X2
WHERE gg=1 OR rn1 = 1
)X3
ORDER BY rn0

Add row number to outer group in t-sql or ssrs

I have a query that returns data with group category and some details like this:
Category | Title
==================
cat1 --- titlex
cat1 --- titley
cat2 --- titley
cat3 --- titlez
cat3 --- titlex
cat4 --- titlex
I want to display a table that has row number on outer group (Category) like this:
RN | Category | Title
======================
1 cat1
titlex
titley
2 cat2
titley
3 cat3
titlez
titlex
4 cat4
titlex
The problem is, when I add RN column as ROW_NUMBER in sql query or ROWNUMBER SSRS function (tried NOTHING, Group and Details as a scope, just in case), I always get numbers like 2 1 2 or 1 3 4 6 for RN column.
EDIT
Sql Query (table names and properties changed for simplicity)
SELECT
-- this rownumber does not work, counts every occurrence of category
--ROW_NUMBER() OVER (
--PARTITION BY c.Name -- tried this too, this resets on each cat
--ORDER BY c.Name) AS RN,
c.Name,
p.Name
FROM
Products p INNER JOIN
Categories c ON p.CategoryId = c.Id
GROUP BY c.Name, p.Name
ORDER BY c.Name, p.Name
You don't want the row numbers (as you've observed, the row numbers are assigned to every... um... row).
Maybe you want DENSE_RANK?
SELECT
DENSE_RANK() OVER (ORDER BY c.Name) AS RN,
c.Name,
p.Name
FROM
Products p INNER JOIN
Categories c ON p.CategoryId = c.Id
GROUP BY c.Name, p.Name
ORDER BY c.Name, p.Name
As to your desired output, I wouldn't attempt to achieve that in SQL - use a reporting/formatting tool to get the final layout.
You can also accomplish this at the presentation layer in SSRS:
=RunningValue(Fields!CategoryFieldName.Value, CountDistinct, Nothing)