sqlconstructor 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE.md +16 -0
  3. data/README.md +161 -0
  4. data/Rakefile +11 -0
  5. data/doc/Object.html +267 -0
  6. data/doc/Rakefile.html +150 -0
  7. data/doc/SQLAliasedList.html +717 -0
  8. data/doc/SQLColumn.html +326 -0
  9. data/doc/SQLCondList.html +318 -0
  10. data/doc/SQLConditional.html +1082 -0
  11. data/doc/SQLConditional/BasicCond.html +325 -0
  12. data/doc/SQLConstructor.html +763 -0
  13. data/doc/SQLConstructor/BasicDelete.html +383 -0
  14. data/doc/SQLConstructor/BasicDelete_mysql.html +368 -0
  15. data/doc/SQLConstructor/BasicInsert.html +339 -0
  16. data/doc/SQLConstructor/BasicInsert_mysql.html +325 -0
  17. data/doc/SQLConstructor/BasicJoin.html +408 -0
  18. data/doc/SQLConstructor/BasicJoin_mysql.html +439 -0
  19. data/doc/SQLConstructor/BasicSelect.html +554 -0
  20. data/doc/SQLConstructor/BasicSelect_example.html +288 -0
  21. data/doc/SQLConstructor/BasicSelect_mysql.html +466 -0
  22. data/doc/SQLConstructor/BasicUnion.html +396 -0
  23. data/doc/SQLConstructor/BasicUpdate.html +409 -0
  24. data/doc/SQLConstructor/BasicUpdate_mysql.html +310 -0
  25. data/doc/SQLConstructor/GenericQuery.html +797 -0
  26. data/doc/SQLConstructor/QAttr.html +398 -0
  27. data/doc/SQLConstructorTest.html +603 -0
  28. data/doc/SQLExporter.html +382 -0
  29. data/doc/SQLExporter/Exporter_generic.html +413 -0
  30. data/doc/SQLExporter/Exporter_mysql.html +395 -0
  31. data/doc/SQLObject.html +525 -0
  32. data/doc/SQLValList.html +322 -0
  33. data/doc/SQLValue.html +375 -0
  34. data/doc/created.rid +12 -0
  35. data/doc/images/brick.png +0 -0
  36. data/doc/images/brick_link.png +0 -0
  37. data/doc/images/bug.png +0 -0
  38. data/doc/images/bullet_black.png +0 -0
  39. data/doc/images/bullet_toggle_minus.png +0 -0
  40. data/doc/images/bullet_toggle_plus.png +0 -0
  41. data/doc/images/date.png +0 -0
  42. data/doc/images/find.png +0 -0
  43. data/doc/images/loadingAnimation.gif +0 -0
  44. data/doc/images/macFFBgHack.png +0 -0
  45. data/doc/images/package.png +0 -0
  46. data/doc/images/page_green.png +0 -0
  47. data/doc/images/page_white_text.png +0 -0
  48. data/doc/images/page_white_width.png +0 -0
  49. data/doc/images/plugin.png +0 -0
  50. data/doc/images/ruby.png +0 -0
  51. data/doc/images/tag_green.png +0 -0
  52. data/doc/images/wrench.png +0 -0
  53. data/doc/images/wrench_orange.png +0 -0
  54. data/doc/images/zoom.png +0 -0
  55. data/doc/index.html +356 -0
  56. data/doc/js/darkfish.js +118 -0
  57. data/doc/js/jquery.js +32 -0
  58. data/doc/js/quicksearch.js +114 -0
  59. data/doc/js/thickbox-compressed.js +10 -0
  60. data/doc/lib/dialects/example-constructor_rb.html +52 -0
  61. data/doc/lib/dialects/mysql-constructor_rb.html +52 -0
  62. data/doc/lib/dialects/mysql-exporter_rb.html +54 -0
  63. data/doc/lib/sqlconditional_rb.html +64 -0
  64. data/doc/lib/sqlconstructor_rb.html +52 -0
  65. data/doc/lib/sqlerrors_rb.html +54 -0
  66. data/doc/lib/sqlexporter_rb.html +55 -0
  67. data/doc/lib/sqlobject_rb.html +54 -0
  68. data/doc/rdoc.css +763 -0
  69. data/doc/test/queries_rb.html +56 -0
  70. data/doc/test_rb.html +52 -0
  71. data/lib/dialects/example-constructor.rb +45 -0
  72. data/lib/dialects/mysql-constructor.rb +247 -0
  73. data/lib/dialects/mysql-exporter.rb +108 -0
  74. data/lib/sqlconditional.rb +196 -0
  75. data/lib/sqlconstructor.rb +708 -0
  76. data/lib/sqlerrors.rb +15 -0
  77. data/lib/sqlexporter.rb +125 -0
  78. data/lib/sqlobject.rb +284 -0
  79. data/test/queries.rb +92 -0
  80. metadata +121 -0
@@ -0,0 +1,15 @@
1
+
2
+ ##################################################################################
3
+ # List of error messages
4
+ ##################################################################################
5
+
6
+ ERR_INVALID_COL_NAME = "Invalid column name."
7
+ ERR_INVALID_RULES = "No valid syntax rules found for dialect"
8
+ ERR_NUMERIC_VALUE_EXPECTED = "Numeric argument value expected."
9
+ ERR_UNKNOWN_DIALECT = "Unimplemented SQL dialect specified"
10
+ ERR_UNKNOWN_METHOD = "Unknown method called"
11
+ ERR_UNKNOWN_OPERATOR_TYPE = "Unknown conditional operator type."
12
+ ERR_VALUES_NUM_MISMATCH = "Number of values provided mismatches the number of requested columns."
13
+ ERR_WHERE_INVALID_ARGS = "Hash expected in .where() arguments."
14
+ ERR_WHERE_LIKE_INVALID_ARGS = "Hash with scalar values expected in .where() arguments."
15
+ ERR_NAME_NOT_FOUND = "Could not find named clause by the name"
@@ -0,0 +1,125 @@
1
+
2
+ ##############################################################################################
3
+ # This class implements the interface for exprting SQLConstructor objects to strings.
4
+ ##############################################################################################
5
+ class SQLExporter
6
+
7
+ attr_accessor :dialect, :tidy
8
+ attr_reader :separator
9
+
10
+ # defaults to 'mysql'
11
+ DEFAULT_DIALECT = 'mysql'
12
+
13
+ #############################################################################
14
+ # Class constructor. Called with two optional arguments - dialect and tidy.
15
+ # Dialect determines the translator class (e.g., Exporter_mysql,
16
+ # Exporter_informix etc). Tidy determines whether the output should be
17
+ # formatted and human-readable.
18
+ #############################################################################
19
+ def initialize ( dialect = DEFAULT_DIALECT, tidy = false )
20
+ dialect ||= DEFAULT_DIALECT
21
+ dialect_class = "Exporter_" + dialect.to_s
22
+ begin
23
+ @translator = SQLExporter.const_get( dialect_class ).new( tidy )
24
+ rescue
25
+ raise NameError, ERR_UNKNOWN_DIALECT + ": " + dialect.to_s
26
+ end
27
+ @dialect, @tidy = dialect, tidy
28
+ @separator = @translator.separator
29
+ end
30
+
31
+ #############################################################################
32
+ # The main method to export the obj to string. Calls the @translator's
33
+ # export method.
34
+ #############################################################################
35
+ def export ( obj )
36
+ string = @translator.export obj
37
+ string = @separator + "(" + string + ")" if obj.inline
38
+ return string
39
+ end
40
+
41
+
42
+ #########################################################################################
43
+ # The exporter class of a 'generic' sql dialect. This should be the parent for
44
+ # all dialect-specific exporter classes.
45
+ #########################################################################################
46
+ class Exporter_generic
47
+
48
+ attr_reader :separator
49
+
50
+ #############################################################################
51
+ # Class constructor.
52
+ #############################################################################
53
+ def initialize ( tidy )
54
+ @tidy = tidy
55
+ @separator = @tidy ? "\n" : " "
56
+ end
57
+
58
+ #############################################################################
59
+ # exports a string with a query from object.
60
+ # this method should be called from a child class with defined constant
61
+ # arrays [select|delete|update|insert]_syntax. methods defined in the array
62
+ # are called in the specified order for the object obj.
63
+ #############################################################################
64
+ def export ( obj )
65
+ rules_const_name = obj.class.name.sub( /^.+?::Basic([^_]+).+/, '\1' ).upcase + "_SYNTAX"
66
+ begin
67
+ rules = self.class.const_get( rules_const_name.to_sym )
68
+ rescue NameError
69
+ raise NameError, ERR_INVALID_RULES + " '" + self.send( :dialect ) + "'"
70
+ end
71
+ string = ""
72
+ rules.each do |rule|
73
+ if rule.is_a? String
74
+ string += rule + @separator
75
+ elsif rule.is_a? Symbol
76
+ res = self.send( rule, obj ).to_s
77
+ string += res
78
+ string += @separator if ! res.empty?
79
+ end
80
+ end
81
+ return string
82
+ end
83
+
84
+ #############################################################################
85
+ # Generic representation of the JOIN clause
86
+ #############################################################################
87
+ def gen_joins ( obj )
88
+ arr_joins = [ ]
89
+ if obj.gen_joins
90
+ arr_joins = obj.gen_joins.map { |join| join.to_s }
91
+ end
92
+ return arr_joins.join( @separator )
93
+ end
94
+
95
+ #############################################################################
96
+ # Construct an expression string for an object's attribute defined in
97
+ # in the METHODS constant array.
98
+ #############################################################################
99
+ def method_missing ( method, *args )
100
+ obj = args[0]
101
+ return '' if ! obj.is_a? SQLObject
102
+ result = ""
103
+ _attr = obj.send method
104
+ if _attr.is_a? Array
105
+ result += _attr.join @separator
106
+ elsif _attr
107
+ result += _attr.to_s
108
+ end
109
+
110
+ return result
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+
117
+ ##################################################################################################
118
+ ##################################################################################################
119
+ # Include dialect-specific classes from ./dialects/exporter/ :
120
+ # This should be done after SQLExporter is defined.
121
+ ##################################################################################################
122
+ ##################################################################################################
123
+
124
+ Dir[ DIALECTS_PATH + "/*-exporter.rb"].each { |file| require file }
125
+
@@ -0,0 +1,284 @@
1
+
2
+ ###############################################################################################
3
+ ### Main class for all objects. All other entities should inherit this class.
4
+ ###############################################################################################
5
+ class SQLObject
6
+
7
+ attr_accessor :alias, :separator, :name, :inline
8
+
9
+ ##########################################################################
10
+ # Do we really need a constructor here?
11
+ ##########################################################################
12
+ def initialize
13
+ @string = nil
14
+ @alias = nil
15
+ @name = nil
16
+ @inline = nil
17
+ end
18
+
19
+ ##########################################################################
20
+ # Set object's name for further named processing
21
+ ##########################################################################
22
+ def _name ( name )
23
+ @name = name.to_s
24
+ return self
25
+ end
26
+
27
+ ##########################################################################
28
+ # Store string representation in @string after the first call
29
+ ##########################################################################
30
+ def to_s
31
+ return @string if @string
32
+ @string = self.to_s
33
+ end
34
+
35
+ ##########################################################################
36
+ # attr_reader for @string, actually an alias to to_s().
37
+ ##########################################################################
38
+ def _string
39
+ to_s
40
+ end
41
+
42
+ ##########################################################################
43
+ # attr_writer for @string
44
+ ##########################################################################
45
+ def _string= ( val )
46
+ @string = val
47
+ end
48
+
49
+ ##########################################################################
50
+ # Convert values to the corresponding internal data types
51
+ ##########################################################################
52
+ def self.get ( *list )
53
+ list.map! do |expr|
54
+ if expr.is_a? SQLObject
55
+ # inline queries go in parens:
56
+ if expr.class == SQLConstructor || expr.is_a?( SQLConstructor::GenericQuery )
57
+ expr.inline = true
58
+ end
59
+ expr
60
+ elsif expr.is_a? Array or expr.is_a? Range
61
+ SQLValList.new *expr.to_a
62
+ elsif expr.is_a? Hash
63
+ SQLAliasedList.new expr
64
+ elsif expr.is_a? Symbol
65
+ SQLColumn.new( expr )
66
+ else
67
+ SQLValue.new( expr )
68
+ end
69
+ end
70
+
71
+ # Return array or scalar, depending on the number of function arguments
72
+ list.length == 1 ? list[0] : list
73
+ end
74
+
75
+ # ##########################################################################
76
+ # # Convert a hash of { obj => alias, ... } to an array of SQLObjects
77
+ # # with defined @alias attribute.
78
+ # ##########################################################################
79
+ # def self.getWithAliases( *list )
80
+ # new_list = [ ]
81
+ # # If list is a hash of objects with aliases:
82
+ # if list.length == 1 && list[0].is_a?( Hash )
83
+ # list.each do |src, _alias|
84
+ # obj = SQLObject.get src
85
+ # obj.alias = _alias
86
+ # new_list << obj
87
+ # end
88
+ # # If list is an array of objects:
89
+ # else
90
+ # new_list = list.map { |src| SQLObject.get src }
91
+ # end
92
+ # return new_list
93
+ # end
94
+
95
+ end
96
+
97
+
98
+ ###############################################################################################
99
+ ### Class representing SQL columns
100
+ ###############################################################################################
101
+ class SQLColumn < SQLObject
102
+
103
+ def initialize ( col = nil )
104
+ @name = col.is_a?( SQLColumn ) ? col.name : col #_prepareName( col )
105
+ end
106
+
107
+ ##########################################################################
108
+ def to_s
109
+ @name.to_s
110
+ end
111
+
112
+ private
113
+
114
+ ##########################################################################
115
+ # Prepare column name (remove all non-alphanumeric/underscore characters)
116
+ ##########################################################################
117
+ def _prepareName ( name )
118
+ name.to_s.gsub /[\W]/, ''
119
+ end
120
+
121
+ end
122
+
123
+
124
+ ###############################################################################################
125
+ ### Class representing SQL scalar values
126
+ ###############################################################################################
127
+ class SQLValue < SQLObject
128
+
129
+ def initialize ( val = nil )
130
+ @value = val.is_a?( SQLValue ) ? val.value : _escape( val )
131
+ end
132
+
133
+ ##########################################################################
134
+ def to_s
135
+ @value
136
+ end
137
+
138
+ private
139
+
140
+ ##########################################################################
141
+ # DERIVED FROM https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
142
+ ##########################################################################
143
+ def _escape ( val )
144
+ case val
145
+ when String then "'#{_quoteString(val.to_s)}'"
146
+ when true then 'TRUE'
147
+ when false then 'FALSE'
148
+ when nil then "NULL"
149
+ when Numeric, Time then val.to_s
150
+ when Symbol then "'#{_quoteString(val.to_s)}'"
151
+ when Class then "'#{val.to_s}'"
152
+ else
153
+ "'#{quoteString( val.to_s )}'"
154
+ end
155
+ end
156
+
157
+ ##########################################################################
158
+ # FROM https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
159
+ # Quotes a string, escaping any ' (single quote) and \ (backslash)
160
+ # characters.
161
+ ##########################################################################
162
+ def _quoteString ( str )
163
+ str.gsub( /\\/, '\&\&' ).gsub( /'/, "''" ) # ' (for ruby-mode)
164
+ end
165
+
166
+ end
167
+
168
+
169
+ ###############################################################################################
170
+ ### Class container - a list of SQLValue scalars
171
+ ###############################################################################################
172
+ class SQLValList < SQLObject
173
+ def initialize ( *list )
174
+ @list = list.map { |item| SQLObject.get item }
175
+ end
176
+
177
+ def << ( list )
178
+ list.map! { |item| SQLObject.get item }
179
+ @list += list
180
+ end
181
+
182
+ def to_s
183
+ return @string if @string
184
+ @string = "(" + @list.join( "," ) + ")"
185
+ end
186
+ end
187
+
188
+
189
+ ###############################################################################################
190
+ ### Class container - a list of SQLObjects with aliases
191
+ ###############################################################################################
192
+ class SQLAliasedList < SQLObject
193
+ attr_writer :no_commas
194
+
195
+ def initialize ( *list )
196
+ @list = _getList *list
197
+ end
198
+
199
+ def << ( *list )
200
+ @list += _getList *list
201
+ return self
202
+ end
203
+
204
+ def push ( *list )
205
+ @list += _getList( *list )
206
+ end
207
+
208
+ def length
209
+ @list.length
210
+ end
211
+
212
+ def each ( &block )
213
+ @list.each &block
214
+ end
215
+
216
+ def delete_if ( &block )
217
+ @list.delete_if &block
218
+ end
219
+
220
+ def [] (i)
221
+ @list[i]
222
+ end
223
+
224
+ def find ( &block )
225
+ @list.find &block
226
+ end
227
+
228
+ def select ( &block )
229
+ @list.each &block
230
+ end
231
+
232
+ def each_with_index ( &block )
233
+ @list.each_with_index &block
234
+ end
235
+
236
+ def to_s
237
+ return @string if @string
238
+ arr = @list.map { |obj| obj.to_s + ( obj.alias ? " " + obj.alias.to_s : "" ) }
239
+ list_separator = @no_commas ? "" : ","
240
+ @string = arr.join list_separator
241
+ end
242
+
243
+ private
244
+
245
+ def _getList ( *list )
246
+ new_list = [ ]
247
+ # If list is a hash of objects with aliases:
248
+ if list.length == 1 && list[0].is_a?( Hash )
249
+ new_list += _hash2array list[0]
250
+ # If list is an array of objects:
251
+ else
252
+ new_list = list.map { |src| SQLObject.get src }
253
+ end
254
+ end
255
+
256
+ def _hash2array ( hash )
257
+ list = [ ]
258
+ hash.each do |item, _alias|
259
+ obj = SQLObject.get item
260
+ obj.alias = _alias
261
+ list << obj
262
+ end
263
+ return list
264
+ end
265
+
266
+ end
267
+
268
+
269
+ ###############################################################################################
270
+ ###
271
+ ###############################################################################################
272
+ class SQLCondList < SQLObject
273
+ def initialize ( hash = { } )
274
+ @hash = Hash[ hash.map{ |k,v| [ SQLObject.get( k ), SQLObject.get( v ) ] } ]
275
+ end
276
+
277
+ def << ( new_hash )
278
+ @hash.merge! new_hash
279
+ end
280
+
281
+ def to_s
282
+ @hash.map{ |k,v| k.to_s + "=" + v.to_s }.join( "," )
283
+ end
284
+ end
@@ -0,0 +1,92 @@
1
+ require 'test/unit'
2
+ require 'sqlconstructor'
3
+
4
+ class SQLConstructorTest < Test::Unit::TestCase
5
+
6
+ def test_select1
7
+ assert_equal "SELECT\n col1,col2\nFROM table1\nJOIN table3 USE INDEX (col1)\nON \n(col1 = ccc1)\nJOIN table4,table5\nON \n(col2 = ccc2 AND col3 = 5)\nWHERE \n(col1 = 123 AND col2 IN ('value1','value2','@\#$%^') AND \n(c1 = 5 AND c2 < 6 OR (c1 = 3 AND c2 IN (1,2,3,4,5) AND s1 = 'somestring')))\nLIMIT 100\nUNION\nSELECT\n baz\nFROM table2\nUNION\nSELECT\n fooz\nFROM table5\nLIMIT 20\n\n",
8
+ select1
9
+ end
10
+
11
+ def test_select2
12
+ assert_equal "SELECT\n t.id,t.tag,c.title category\nFROM tags2Articles t2a\nINNER JOIN tags t\nON \n(t.id = t2a.idTag)\nINNER JOIN categories c\nON \n(t.tagCategory = c.id)\nINNER JOIN \n(SELECT\n a.id\nFROM articles a\nJOIN tags2articles ta\nON \n(a.id = ta.idArticle)\nJOIN tags tsub\nON \n(ta.idTag = tsub.id)\nWHERE \n(tsub.id IN (12,13,16))\nGROUP BY a.id\nHAVING \n(COUNT(DISTINCT tsub.id) = 3)\n) asub\nON \n(t2a.idArticle = asub.id)\n",
13
+ select2
14
+ end
15
+
16
+ def test_insert1
17
+ assert_equal "INSERT\nINTO table2\n SELECT\n name,CONCAT('blah=',ID)\nFROM table1\n\n",
18
+ insert1
19
+ end
20
+
21
+ def test_delete1
22
+ assert_equal "DELETE\nFROM keywords\nWHERE \n(keyword_id IN \n(SELECT\n id\nFROM \n(SELECT\n k.keyword id\nFROM keywords k\nWHERE \n(k.keyword_type = 'CAMPAIGN' AND k.keyword != 'Airtel' AND k.keyword != 'Nokia' AND k.keyword != 'Micromax' AND k.keyword NOT IN \n(SELECT\nDISTINCT\n keyword_id\nFROM customer_analysis\n))\nORDER BY k.keyword_id\n) a\n))\n",
23
+ delete1
24
+ end
25
+
26
+ def test_update1
27
+ assert_equal "UPDATE\n guest g\nSET link_id=\n(SELECT\n MAX(h.host_id)\nFROM guest_data d\nINNER JOIN host_data h\nON \n(d.guest_nm = hhost_nm)\nWHERE \n(d.guest_id = g.guest_id)\nGROUP BY h.venue_nm\nHAVING \n(COUNT(*) = 1)\n)\nWHERE \n(g.guest_id IN \n(SELECT\n d.guest_id\nFROM guest_data d\nINNER JOIN host_data h\nON \n(d.guest_nm = hhost_nm)\nGROUP BY h.venue_nm\nHAVING \n(COUNT(*) = 1)\n))\n",
28
+ update1
29
+ end
30
+
31
+ def select1
32
+ sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
33
+ sql.select(:col1,:col2).from(:table1).where.eq(:col1, 123).and.in(:col2,["value1","value2","@#\$%^"])
34
+ sql.limit( 100 )
35
+ sql.union._name("u1").select(:baz).from(:table2)
36
+ c2 = SQLConditional.new.eq(:c1,3).and.in(:c2,[1,2,3,4,5]).and.eq(:s1,'somestring')
37
+ c1 = SQLConditional.new.eq(:c1,5).and.lt(:c2,6).or.is(c2)
38
+ sql.where.and.is(c1)
39
+ sql.join( :table3 )._name('j1').on.eq( :col1, :ccc1 ).use_index( :col1 )
40
+ sql.join( :table4,:table5 )._name('j2').on.eq( :col2, :ccc2).and.eq( :col3, 5 )
41
+ sql.union._name("u2").select(:fooz).from(:table5).limit( 20 )
42
+ sql.to_s
43
+ end
44
+
45
+ def select2
46
+ sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
47
+ sql.select( :"t.id",:"t.tag",:"c.title" => :category ).from( :tags2Articles => :t2a )
48
+ sql.inner_join( :tags => :t ).on.eq(:"t.id", :"t2a.idTag" )
49
+ sql.inner_join( :categories => :c ).on.eq( :"t.tagCategory", :"c.id" )
50
+ inner_sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
51
+ inner_sql.select( :"a.id" ).from( :articles => :a )
52
+ inner_sql.join( :tags2articles => :ta ).on.eq( :"a.id", :"ta.idArticle" )
53
+ inner_sql.join( :tags => :tsub ).on.eq( :"ta.idTag", :"tsub.id" )
54
+ inner_sql.where.in( :"tsub.id", [12,13,16] ).group_by( :"a.id" ).
55
+ having.eq( :"COUNT(DISTINCT tsub.id)", 3 )
56
+ sql.inner_join( inner_sql => 'asub' ).on.eq( :"t2a.idArticle", :"asub.id" )
57
+ sql.to_s
58
+ end
59
+
60
+ def insert1
61
+ sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
62
+ sql.insert.into(:table2).select(:name, :"CONCAT('blah=',ID)").from(:table1)
63
+ sql.to_s
64
+ end
65
+
66
+ def delete1
67
+ sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
68
+ inner_sel3 = SQLConstructor.new( :tidy => true, :dialect => 'mysql' ).select( :keyword_id ).distinct.from( :customer_analysis )
69
+ inner_sel2 = SQLConstructor.new( :tidy => true, :dialect => 'mysql' ).select( :"k.keyword" => :id ).from( :keywords => :k ).
70
+ where.eq( :"k.keyword_type", "CAMPAIGN" ).and.ne( :"k.keyword", "Airtel" ).
71
+ and.ne( :"k.keyword", "Nokia" ).and.ne( :"k.keyword", "Micromax" ).
72
+ and.not_in( :"k.keyword", inner_sel3 ).order_by( :"k.keyword_id" )
73
+ inner_sel1 = SQLConstructor.new( :tidy => true, :dialect => 'mysql' ).select( :id ).from( inner_sel2 => :a )
74
+ sql.delete.from( :keywords ).where.in( :keyword_id, inner_sel1 )
75
+ sql.to_s
76
+ end
77
+
78
+ def update1
79
+ sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
80
+ in_sel1 = SQLConstructor.new( :tidy => true )
81
+ in_sel1.select( :"MAX(h.host_id)" ).from( :guest_data => :d ).
82
+ inner_join( :host_data => :h ).on.eq( :"d.guest_nm", :hhost_nm ).where.
83
+ eq( :"d.guest_id", :"g.guest_id" ).group_by( :"h.venue_nm" ).having.eq( :"COUNT(*)", 1 )
84
+ in_sel2 = SQLConstructor.new( :dialect => 'mysql', :tidy => true )
85
+ in_sel2.select( :"d.guest_id" ).from( :guest_data => :d ).
86
+ inner_join( :host_data => :h ).on.eq( :"d.guest_nm", :hhost_nm ).
87
+ group_by( :"h.venue_nm" ).having.eq( :"COUNT(*)", 1 )
88
+ sql.update( :guest => :g ).set( :link_id => in_sel1).where.in( :"g.guest_id", in_sel2 )
89
+ sql.to_s
90
+ end
91
+
92
+ end